從零搭建項目(5) --- 前端: 搭建路由和狀態(tài)管理

我的博客地址

正式地址
測試地址
前端源碼
后端源碼

文章目錄

  1. 項目及其技術(shù)棧介紹
  2. 前端: 項目初始化
  3. 前端: 使用Sass和Antd
  4. 前端: 開發(fā)體驗優(yōu)化
  5. 前端: 搭建路由和狀態(tài)管理
  6. 前端: 支持Axios
  7. 前端: 打包與環(huán)境變量設(shè)置
  8. 前端: 團(tuán)隊代碼規(guī)范
  9. 后端: 項目初始化和使用Koa相關(guān)
  10. 后端: 使用TypeORM和MySQL
  11. 部署: 使用nginx部署前端項目
  12. 部署: 后端部署
  13. 部署: 使用jenkins自動化部署

前言

該篇博客介紹如何使用react-router4+搭建前端路由,并使用最新的suspense和lazy構(gòu)建路由的按需加載。同時介紹狀態(tài)管理的搭建,其中在狀態(tài)管理搭建中,會嘗試使用最新的useReducer+context來搭建前端的狀態(tài)管理,以及他與TypeScript之間的配合。

  1. React Router4+,suspense,lazy
  2. useReducer + context

前端路由搭建

  • 安裝react-router
    首先我們需要安裝react-router以及他的類型文件
    npm i -S react-router-dom
    npm i -D @types/react-router-dom
    在這里說一下react-routerreact-router-dom之間的區(qū)別:
    react-routerreact-router-dom的核心代碼,提供理由的核心api,例如Router、Route、Switch等,而react-router-dom提供了BrowserRouter,Link等api,react-router-dom里面包含了react-router,所以一般只需要安裝react-router-dom

  • 編寫路由頁面
    然后我們在src/containers/views中編寫兩個路由頁面PageAPageB

    image.png

  • 接著我們還是在src/containers/views中新建App組件,并在App組件下新建routerMap.tsx文件用作存放路由表。
    routerMap文件中,我們引入lazy方法,并通過import()引入PageAPageB,然后通過統(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ù)棧中我們通常使用MobxRedux進(jìn)行前端狀態(tài)管理,但在本項目中未采用這兩個庫,而是使用了useReducer + context的方式來進(jìn)行搭建,而本文中則使用一個加減計數(shù)器的方式來展示如何搭建和使用useReducer + context狀態(tài)管理

進(jìn)行這一步之前首先需要知道如何使用useContext、createContext以及useReducer

  • 首先我們在src文件夾下新建兩個文件夾storecomponents,其中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.tsxprops的報錯則可以使用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中我們放入的是statedispatch,所以這兩個都需要進(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)入所有的ProvideruseXXXStore,然后組成一個數(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文件夾中新建兩個組件CountOperationShowCount:

image.png

image.png

然后在里面將useTestStore方法從store引入,這個方法執(zhí)行后可以得到statedispatch
image.png

image.png

并且這些都是帶有類型提示的,說明我們的ts和useReducer + context結(jié)合得非常棒了:
image.png

最后把這兩個組件在PageA頁面中引入進(jìn)行成果驗證:

image.png

查看結(jié)果:
image.png

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

image.png

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容