這是Webpack+React系列配置過程記錄的第六篇。其他內(nèi)容請參考:
- 第一篇:使用webpack、babel、react、antdesign配置單頁面應(yīng)用開發(fā)環(huán)境
- 第二篇:使用react-router實現(xiàn)單頁面應(yīng)用路由
- 第三篇:優(yōu)化單頁面開發(fā)環(huán)境:webpack與react的運行時打包與熱更新
- 第四篇:React配合Webpack實現(xiàn)代碼分割與異步加載
- 第五篇:分離Webpack開發(fā)環(huán)境與生產(chǎn)環(huán)境的配置
- 第六篇:在React中使用Redux
這篇文章的主要內(nèi)容包括:
- 修改一下之前存在的問題;
- 在框架中引入redux,使用一個例子簡單介紹redux的使用方法;
- 其他redux輔助庫。
修復(fù)遺留問題
- webpack.prod.config.js中缺少了對path庫的引用,執(zhí)行構(gòu)建
npm run build:prod
的時候失敗。在文件開始的地方引入node.js的path庫就可以了。 - package.json里面定義了一個build:dev的腳本,這個腳本其實有點多余,不過有時候需要打包測試版本的文件,所以還是需要存在。主要有個問題是webpack.dev.config.js中output節(jié)點下錯誤定義了path的值為根目錄'/',這在使用
npm start
命令啟動運行時打包的時候看不出問題,但是在使用npm run build:dev
時會出現(xiàn)無法寫文件到根目錄的權(quán)限錯誤。只要把path的值改掉就可以。path: config.publicPath
改成path: config.staticPath,publicPath: config.publicPath
。 - css-loader和less-loader導(dǎo)出的樣式類名太長,還是把localIdentName中的path部分去掉比較好看。
redux
安裝redux
安裝依賴的命令如下:
npm install --save redux react-redux redux-thunk
npm install --save-dev redux-logger
redux不用說了,我是把它當(dāng)成一個本地數(shù)據(jù)庫使用,react-redux幫助你完成數(shù)據(jù)訂閱,redux-thunk可以放你實現(xiàn)異步action,redux-logger是redux的日志中間件。
關(guān)于redux與代碼布局
在開始介紹之前我想先就redux的使用發(fā)表一些自己的看法:
前文說了我把redux當(dāng)成一個本地數(shù)據(jù)庫,因此我傾向于把redux封裝類似于mvc中的Model的角色,獨立為一層。這與另一種觀點——我在公司的項目更傾向于把每個頁面當(dāng)成一個獨立模塊,每個模塊維護(hù)自己的reducer和action的觀點,有所出入。
我的做法可以更好地實現(xiàn)reducer的復(fù)用。而對我自己來說更重要的好處是集中修改。更適合小項目或者獨自開發(fā)一個項目的場景。
我公司的項目的做法對多人協(xié)同開發(fā)更有利,畢竟每個人維護(hù)好自己的代碼就可以了。公司項目的這種方法有幾個問題讓我比較難以接受:
第一個是模塊越多reducer和action的定義越多,很多時候這些代碼都是差不多的。
更重要的是第二個問題:模塊數(shù)據(jù)在store里面的存儲是直接在根state下面排列下來的,根state的數(shù)據(jù)格式樣式有點像這樣:
{
aModuleData:{...},
bModuleData:{...},
cModuleData:{...},
dModuleData:{...},
...
}
項目的原意是希望每個模塊的保持獨立,但實際上使用的時候卻是有極大的可能出現(xiàn)aModule同時使用aModuleData和bModuleData的情況。這跟每個人維護(hù)自己的代碼的初衷有悖,也沒有發(fā)揮好redux的真正能力。
還有一個小問題是reducer的組織通常影響著應(yīng)用數(shù)據(jù)state的樣式,把reducer分散到每個模塊之后,state的形式在代碼上很難直管地反映出來,特別是當(dāng)模塊是動態(tài)加載的時候更甚。不過借助logger等工具可以解決。
關(guān)于這塊的爭議Redux的教程中有提及。
使用redux
無論代碼怎么布局,使用redux的方法主要還是三步曲:創(chuàng)建store、創(chuàng)建action、創(chuàng)建reducer。而在這之后才是與業(yè)務(wù)或者組件相關(guān)的數(shù)據(jù)處理和展示。
先看一下我的做法的代碼布局:
創(chuàng)建store的代碼集中在model/index.js中,model/actions/.js和model/reducer/.js里面分別是寫action創(chuàng)建函數(shù)和reducer函數(shù)的地方,根據(jù)模塊可以自己DIY。
model/index.js的代碼如下:
model/actions/index.js的代碼如下:
這里定義了一個名叫l(wèi)ogin的異步actionCreator以及三個普通的actionCreator。
actionCreator被某個組件調(diào)用后會向store發(fā)送action,然后被reducer處理,reducer定義在model/reducers/index.js中,代碼如下:
這就完成了三步曲了。上面的代碼簡單地模擬了登錄的動作。登錄頁面用到的數(shù)據(jù)存放在loginPageData中,登陸后獲取到的當(dāng)前登錄用戶數(shù)據(jù)存儲在實體數(shù)據(jù)entities中。
接下來要把redux和react聯(lián)系起來,也就是把redux的store中的數(shù)據(jù)交給react的組件使用。
第一步需要掛載redux的store到react,為react提供數(shù)據(jù)支持。最簡單的做法是找到應(yīng)用的根組件(我這里是BasicExample.js),然后在它的render函數(shù)中最外層添加Providor標(biāo)簽。代碼片段如下:
紅線部分畫出了改動點,從model/index.js中導(dǎo)出了store對象,通過react-redux提供的Providor標(biāo)簽掛載到react中,為react提供數(shù)據(jù)支持。
看最后的紅線中,我們在Home組件里面添加了這次的測試?yán)覴eduxDemo。它的代碼如下:
代碼的重點在connect函數(shù)。這個函數(shù)也是由react-redux提供的。使用它可以包裝普通的展示組件(這里是ReduxDemo——只負(fù)責(zé)展示數(shù)據(jù)),然后返回一個容器組件。connect函數(shù)通過第一個參數(shù)讓展示組件訂閱了來自store的數(shù)據(jù);通過第二個參數(shù)讓展示組件默認(rèn)可以dispatch各種action。
這個例子在ReduxDemo掛載完成后調(diào)用login接口模擬登陸。返回結(jié)果被塞到store中(數(shù)據(jù)格式由先前寫好的reducers的組織方式?jīng)Q定)。頁面根據(jù)store中的數(shù)據(jù)展示內(nèi)容。由于login發(fā)出的遠(yuǎn)程請求是假的,所以這里總是失敗,因此會顯示失敗的內(nèi)容。
關(guān)于redux的使用介紹到此結(jié)束。
redux輔助庫
其實在上面的代碼中我已經(jīng)悄悄地提及了兩個輔助庫,也是我想在這里推薦的兩個庫:
- 開發(fā)工具redux-devtools:結(jié)合各種其他庫可以實現(xiàn)可視化的調(diào)試界面。
- 數(shù)據(jù)規(guī)范化工具normalizr:規(guī)范化組織數(shù)據(jù)。經(jīng)過三個項目的體驗后,個人非常推薦使用這個庫,可以讓應(yīng)用的數(shù)據(jù)組織更清晰、減少冗余數(shù)據(jù)、減少因數(shù)據(jù)刷新導(dǎo)致的性能影響。
暫時不在這里展開介紹,有興趣的可以到github上查一下文檔。