- 上一篇咱們配置了項目相關,包括代碼壓縮混淆,開發生產配置抽離,圖片與文字的引入使用等
- 接下來咱們就配置一下react-router,react-redux與typescript
- 配置以前咱們先補充一下webpack的部分配置,用於方便咱們的開發
- 在webpack.common.js中配置webpack的查找規則,也就是resolve,以下
...
module.exports = {
entry: {
...
},
module: {
...
},
resolve: {
extensions: ['.jsx', '.js', '.json'],
alias: {
"@": path.resolve(__dirname, 'src')
}
},
plugins: [
...
],
optimization: {
...
}
}
複製代碼
- 上面新增了一個resolve的解析規則,使webpack方便查找,第一個extensions中的配置表示咱們在引入後綴爲.jsx,.js,.json的文件時,能夠直接寫文件名而不用加後綴,好比引入'./index.jsx',咱們就能夠直接寫爲'./index'
- 下面的alias就是別名配置,用於在引入路徑時方便使用,好比咱們在項目中有以下的代碼結構
src
├── lib
│ └── utils.js
└── pages
└── demo
└── index.js
複製代碼
- 在 src/pages/demo/index.js 中若是要引用 src/lib/utils.js 那麼能夠經過:import utils from '../../lib/utils' ,若是目錄更深一些,會愈來愈難看,這時能夠經過設置 alias 來縮短這種寫法,例如:
module.exports = {
resolve: {
'@': path.resolve(__dirname, 'src'),
'@lib': path.resolve(__dirname, 'src/lib')
}
}
複製代碼
- 這樣咱們就能夠直接使用 '@lib/utils'來進行文件的引入了
react-router的使用
- 配置完resolve以後咱們就開始進行react-router的配置了,仍是先下載react-router-dom模塊,命令爲: npm i react-router-dom -S
- 而後在src下新建兩個頁面,pages/login.jsx與pages/home.jsx做爲咱們的路由頁面
import React from 'react'
const Home = () => {
return (
<div>我是首頁</div>
)
}
export default Home
import React from 'react'
const Login = () => {
return (
<div>我是登陸頁</div>
)
}
export default Login
複製代碼
- 接着在src下新建routes/index.jsx文件做爲咱們的路由管理頁面
- 在文件內引入react與react-router-dom,而後引入新建的login頁面與home頁面
- 頁面代碼以下
import React from 'react'
import { HashRouter as Router, Route, Switch, Redirect } from 'react-router-dom'
import Login from '@/pages/login'
import Home from '@/pages/home'
const RouteConfig = () => {
return (
<Router> <Switch> <Route path="/home" component={ Home }></Route> <Route path="/login" component={ Login }></Route> <Redirect to="/home" from="/"></Redirect> </Switch> </Router>
)
}
export default RouteConfig
複製代碼
- 而後在app.jsx裏面以組件的形式引入咱們的路由便可,以下
import * as React from 'react'
import './app.less'
import RouteConfig from '@/route/index'
class App extends React.Component{
render(){
return (
<RouteConfig></RouteConfig>
)
}
}
export default App
複製代碼
- 而後運行npm run dev就能發現自動幫咱們定位到/home頁面,咱們手動修改路由爲/login就能夠發現頁面跳轉到了login頁面
- 至此,咱們的react-router就配置完成了
react-redux的使用
- redux是經常使用的狀態管理組件,用於維護全局的數據變量,react項目中天然也須要它的存在,下面咱們就配置一下redux
- 在react中使用redux須要引入redux與react-redux,仍是先安裝包: npm i redux react-redux -S
- 而後在src下新建文件夾store用於放置咱們的redux相關文件
- redux在數據比較複雜的時候會按照模塊來放置文件,最後再用redux提供的api組合起來,方便後續的維護,這裏咱們創立數字模塊number與聊天模塊chat,分別在store下面創建兩個文件夾store/chat與store/number
- 在每一個文件夾下面創建咱們會用到的操做該數據的操做類型與該操做類型下的數據變化狀況,分別對應types.js與reducers.js
- 先構建store/number下的types與reducers,對外提供加減兩個方法,先在types下構建常量用於標識對應的方法
export const INCREMENT = 'INCREMENT'
export const DECREMENT = 'DECREMENT'
複製代碼
- 而後再編寫該方法下的數據變化狀況reducers,併爲這個數字模塊設立初始值0,當執行方法爲加減的時候就在原基礎上加減對應的值,不然就原樣返回
import { INCREMENT, DECREMENT } from './types'
const initialState = 0
const numberReducer = (state = initialState, action) => {
switch(action.type) {
case INCREMENT:
return state + action.payload
case DECREMENT:
return state - action.payload
default:
return state
}
}
export default numberReducer
複製代碼
- 上面就是簡單的數字模塊的兩個方法了,而後咱們一樣實現一下chat模塊的方法
export const SEND = 'SEND'
export const DELETE = 'DELETE'
import { SEND, DELETE } from './types'
const initialState = []
const chatReducer = (state = initialState, action) => {
switch(action.type) {
case SEND:
return [...state, action.payload]
case DELETE:
return state.length ? state.slice(0, state.length - 1) : []
default:
return state
}
}
export default chatReducer
複製代碼
- chat模塊提供了一個發送方法與刪除方法用於操做聊天列表
- 接下來咱們就要使用redux提供的combineReducers方法將其合併起來
- 在store下新建index.js文件用於最後的導出
- 在index.js中引入combineReducers,chat模塊,number模塊,而後合併並導出,以下
import { combineReducers } from 'redux'
import ChatReducer from './chat/reducers'
import NumberReducer from './number/reducer'
const rootReducer = combineReducers({
number: NumberReducer,
chat: ChatReducer
})
export default rootReducer
複製代碼
- 上面就完成了redux的編寫,接下來就要在react根組件上將其使用
- 在index.jsx中引入store/index.js,引入redux提供的方法createStore建立全局狀態,引入react-redux中的Provider包裝根組件,以下
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import App from './src/app.jsx'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import RootReducer from '@/store/index'
const store = createStore(RootReducer)
ReactDOM.render(
<Provider store={ store }> <App/> </Provider>
,document.querySelector('#app')
)
複製代碼
- 上面就在咱們的項目中引入了redux,接下來就是使用,咱們在login組件中嘗試使用number並修改
- 在login組件中引入對應的操做方法與react-redux提供的connect方法,而後修改咱們的login組件以下
import React from 'react'
import { connect } from 'react-redux'
import { INCREMENT, DECREMENT } from '@/store/number/types'
const Login = (props) => {
const { number, increment, decrement } = props
return (
<div> <button>我是數字{ number }</button> <button onClick={() => { increment() } }>點我加10</button> <button onClick={() => { decrement() } }>點我減10</button> </div>
)
}
function mapStateToProps(state){
return {
number: state.number
}
}
function mapDispatchToProps(dispatch){
return {
increment: () => dispatch({ type: INCREMENT, payload: 10 }),
decrement: () => dispatch({ type: DECREMENT, payload: 10 })
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Login)
複製代碼
- connect中的第一個參數接受兩個函數,分別用於整合state到props中跟整合操做方法到props中,這樣咱們就能夠在頁面中使用該方法與該值了
- 修改以後咱們點擊兩個按鈕就能夠看到對應值的變化了
react中引入typescript
- typescript當下如此潮流咱們天然也要接入一下啦,下面就是簡單的接入過程
- 得益於咱們強大的babel-7,咱們再也不須要去單獨的使用ts-loader或者awesome-typescript-loader解析ts文件,只須要在babel中進行typescript的相關配置便可
- 首先仍是先安裝咱們的typescript與@babel/preset-typescript,命令爲: npm i typescript @babel/preset-typescript -D
- 而後再.babelrc文件中進行typescript的配置,以下
{
"presets": [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-rtpescript",
],
"plugins": [
"@babel/proposal-object-rest-spread",
"@babel/proposal-class-properties"
]
}
複製代碼
- 而後在webpack中對typescript文件配置babel解析便可,這是一個通用配置,因此仍是在webpack.common.js上修改,以下
module.exports = {
entry: {
},
module: {
rules: [
{
test: /\.(js|ts)x?$/,
use: ['babel-loader'],
exclude: /node-modules/
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
alias: {
"@": path.resolve(__dirname, 'src')
}
},
plugins: [
...
],
optimization: {
...
}
}
複製代碼
- 而後就要配置typescript中的編譯規則,在根目錄下新建tsconfig.json文件,而後添加以下配置
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"outDir": "./dist/",
"noImplicitAny": true,
"module": "es6",
"target": "esnext",
"jsx": "react",
"allowJs": true,
"sourceMap": true,
"lib": [
"es2015",
"dom.iterable",
"es2016.array.include",
"es2017.object",
"dom"
],
"moduleResolution": "node",
"baseUrl": "./src",
"paths": {
"store/*": ["store/*"],
},
},
"include": [
"src"
],
"exclude": [
"./node_modules"
]
}
複製代碼
- 由於咱們以前配置了別名,因此須要加上後面的配置中的baseUrl與paths保證typescript可以找到對應的配置,其餘的都是typescript的基本配置
- 接下來咱們嘗試將入口文件修改成tsx嘗試一下,在webpack.common.js中將入口文件改成app:'index.tsx',而後再將index.jsx後綴改成tsx,以後運行npm run dev發現報錯 can not find module 'react',就說明咱們的typescript已經配置完成了,能夠正常檢查錯誤
- 上述錯誤是由於咱們在TS中進行的開發,TS並不知道咱們的react是什麼類型,導出了什麼,因此就報錯了,這裏咱們就須要安裝react相關的類型文件
- 項目中咱們使用了react,react-dom,react-redux,react-router-dom這四個依賴,因此咱們就須要安裝依賴包,命令爲:npm i @types/react @types/react-dom @types/react-redux @types/react-router-dom -S
- 以後咱們再次編譯,就發現項目能夠正常運行了。
- 可是使用上面的配置以後發現,在咱們編譯過程當中類型出錯webpack並不會提示咱們出錯,這是由於babel7中在編譯過程會移除typescript,徹底以javascript的形式進行打包,詳見(https://iamturns.com/typescript-babel)。由於,要把babel跟typescript同時編譯,兩個編譯器會致使過程十分緩慢,這但是開發者不能容忍的。針對這種狀況,咱們能夠新建一個命令 "check": "tsc -watch",而後使用vscode帶給咱們的終端啓用兩個終端,一個運行命令 npm run check,另外一個運行命令npm run dev,這樣就發現咱們在開發中出現的類型錯誤都會在check的終端對咱們進行提示。
- 接下來咱們只須要將全部的jsx文件轉爲tsx文件就能夠進行typescript的開發了,項目地址react-admin,能夠自行獲取配置進行修改