我的博客地址
文章目錄
- 項目及其技術(shù)棧介紹
- 前端: 項目初始化
- 前端: 使用Sass和Antd
- 前端: 開發(fā)體驗優(yōu)化
- 前端: 搭建路由和狀態(tài)管理
- 前端: 支持Axios
- 前端: 打包與環(huán)境變量設(shè)置
- 前端: 團(tuán)隊代碼規(guī)范
- 后端: 項目初始化和使用Koa相關(guān)
- 后端: 使用TypeORM和MySQL
- 部署: 使用nginx部署前端項目
- 部署: 后端部署
- 部署: 使用jenkins自動化部署
前言
該篇博客介紹如何使用react-router4+搭建前端路由,并使用最新的suspense和lazy構(gòu)建路由的按需加載。同時介紹狀態(tài)管理的搭建,其中在狀態(tài)管理搭建中,會嘗試使用最新的useReducer+context來搭建前端的狀態(tài)管理,以及他與TypeScript之間的配合。
- React Router4+,suspense,lazy
- useReducer + context
前端路由搭建
安裝react-router
首先我們需要安裝react-router以及他的類型文件
npm i -S react-router-dom
npm i -D @types/react-router-dom
在這里說一下react-router和react-router-dom之間的區(qū)別:
react-router是react-router-dom的核心代碼,提供理由的核心api,例如Router、Route、Switch等,而react-router-dom提供了BrowserRouter,Link等api,react-router-dom里面包含了react-router,所以一般只需要安裝react-router-dom-
編寫路由頁面
然后我們在src/containers/views中編寫兩個路由頁面PageA和PageB
image.png -
接著我們還是在
src/containers/views中新建App組件,并在App組件下新建routerMap.tsx文件用作存放路由表。
在routerMap文件中,我們引入lazy方法,并通過import()引入PageA和PageB,然后通過統(tǒng)統(tǒng)放到一個數(shù)組中,將這個數(shù)組導(dǎo)出去:
image.png -
我們?nèi)サ?code>App/index.tsx中,從
react-router-dom中導(dǎo)入BrowserRouter, Route和Switch,以及從React中導(dǎo)入Suspense組件,然后編寫路由文件,并將其用Suspense包裹起來,使用了lazy方法導(dǎo)入的組件必須用Suspense包裹,否則不能加載出來并報錯:
image.png -
在這里需要注意的是,如果使用的是
BrowserRouter,需要在webpack中加上devServer配置,并打開historyApiFallback,原因是當(dāng)跳轉(zhuǎn)到page-b頁面的時候,他會試圖尋找page-b.html,但我們是單頁應(yīng)用,所以沒有這個文件,從而出現(xiàn)找不到的情況,而historyApiFallback會在找不到頁面的情況下跳轉(zhuǎn)回index.html,避免直接出現(xiàn)找不到的情況:
image.png
-
最后我們回到頁面查看跳轉(zhuǎn)情況:
路徑為/的時候加載PageA:
image.png
當(dāng)路徑切換為/page-b的時候,則加載PageB:
image.png
這時候我們的前端路由就搭建好了,并且可以進(jìn)行動態(tài)加載 -
使用
withRouter方法進(jìn)行路由跳轉(zhuǎn)
去到PageA頁面添加如下代碼:
image.png
image.png
這時候點擊跳轉(zhuǎn)B按鈕的時候就能夠跳轉(zhuǎn)到/page-b路徑了:
image.png
狀態(tài)管理搭建
在React技術(shù)棧中我們通常使用Mobx,Redux進(jìn)行前端狀態(tài)管理,但在本項目中未采用這兩個庫,而是使用了useReducer + context的方式來進(jìn)行搭建,而本文中則使用一個加減計數(shù)器的方式來展示如何搭建和使用useReducer + context狀態(tài)管理
進(jìn)行這一步之前首先需要知道如何使用useContext、createContext以及useReducer
-
首先我們在
src文件夾下新建兩個文件夾store和components,其中store用于存儲共用狀態(tài)和配置,components用于存放組件。
image.png -
然后我們在
store文件夾中新建index.tsx文件和count文件夾,在count文件夾中新建index.tsx、reducer.ts以及types.d.ts文件:
image.png -
其中
index.tsx文件用于存放Provider和初始狀態(tài),如下圖:
image.png -
然后在
reducer.ts中,我們開始編寫reducer:
image.png
編寫完成在index.tsx中導(dǎo)入:
image.png -
解決類型報錯問題
這時候你會發(fā)現(xiàn)reducer和index.tsx中都存在很多報錯,這是因為沒有添加類型導(dǎo)致ts認(rèn)為他們是any類型,所以我們?yōu)樗麄兲砑宇愋臀募?br> 我們?nèi)サ街靶陆ǖ?code>types.d.ts文件中,定義好state的接口和action的類型,為了避免今后store變得原來越大,我們使用命名空間來避免命名沖突:
image.png
之后到reducer.ts將類型補充上去:
image.png
而index.tsx中props的報錯則可以使用React自帶的ComponentType類型將Provider定義為組件類型以解決:
image.png
image.png -
定義Context的類型
另外有些小伙伴可能會有如下ts錯誤:
image.png
這是因為我們在createContext中傳入的參數(shù)為null導(dǎo)致的。
要解決這個問題首先我們?nèi)サ?code>src/types文件夾中新增context.d.ts文件,接著定義Context的類型,注意因為之前在Context的value中我們放入的是state和dispatch,所以這兩個都需要進(jìn)行定義,而state和dispatch每個store可能都不一樣,所以需要用到泛型:
image.png
之后到index.tsx中進(jìn)行使用,注意這里我們從react中導(dǎo)入了Dispatch類型:
image.png
最后我們到tsconfig.json中將strictNullChecks的屬性設(shè)置為false:
image.png
-
最后我們回到
store/index.tsx文件中,導(dǎo)入所有的Provider和useXXXStore,然后組成一個數(shù)組,通過一個總的Provider進(jìn)行導(dǎo)出:
image.png
然后到src/index.tsx中導(dǎo)入這個總的Provider,并使用它包裹<App />組件
image.png -
驗證成果
驗證成果之前我們需要先將store和components的路徑別名分別添加進(jìn)webpack和tsconfig中去,不動怎么添加的看我上一篇文章:
image.png
image.png
我們到之前新建的components文件夾中新建兩個組件CountOperation和ShowCount:


然后在里面將
useTestStore方法從store引入,這個方法執(zhí)行后可以得到state和dispatch

并且這些都是帶有類型提示的,說明我們的ts和
useReducer + context結(jié)合得非常棒了:
最后把這兩個組件在PageA頁面中引入進(jìn)行成果驗證:

查看結(jié)果:

這樣我們的useReducer + context的狀態(tài)管理方案就完成了。
難點我估計在于對Context的類型編寫,因為這一塊會用到嵌套的泛型,而泛型在TypeScript中是一個難點,但這個難點是必須攻克的:


























