最近在用react寫web項目,領導為了讓前端便於維護要求都用react作為開發基礎,框架選型不限。在使用 react 的時候或多或少會接觸到狀態管理,從開始學 react 到現在也挺久了,做一些前端框架選型總結。
dva
經朋友推薦開始接觸 dva ,從 2.x 版本開始使用,我也基於這個工具開發了一套項目模版,它簡化了 redux 的使用,並且在封裝了 redux-saga 和 react-router,同時還可以包含 dva-loading 插件獲取 loading 狀態等。
在 redux 時代,當我需要新增一種跨頁面全局數據的時候,我需要去項目的 reducers 目錄定義一下這種數據命名和初始值,然后在 constans 目錄中為更改這項數據的操作定義一種唯一的操作類型(type),再去 actions 目錄定義一些方法,這些方法最后會得到更改后的數據和操作類型(type),最后再回到 reducers 中根據這個操作類型(type)把數據整合到 reducer 中…可以看到,我在編寫 redux 這部分代碼的時候需要頻繁在 actions 、 constants 、 reducers 這幾個目錄間切換。
而使用 dva 就可以免除這些困擾了,我只需要一個 model 中就可以完成所有操作:
// app全局性狀態管理 import * as appApis from '../services/app'; // 異步請求接口 export default { namespace: 'app', state: { channels: [], show: true }, reducers: { getChannelsAndGamesSuccess(state, { channels, games }) { return { ...state, channels, games }; }, changeShow(state, { show }) { return { ...state, show }; } }, effects: { // 異步 * getChannelsAndGames(_, { call, put }) { const res = yield call(appApis.getChannelsAndGames); yield put({ type: 'getChannelsAndGamesSuccess', channels: res.channels }); } }, subscriptions: { // 訂閱 setup({dispatch, history}) { history.listen(location => { if (location.pathname == '/') { dispatch({ type: 'getChannelsAndGames' }); } }); } } };
這便是一個 model 對象,state 定義數據、effects 中執行異步請求、觸發 action 在 reducers 中改變數據,一氣呵成!
此外它還含有其他特性,比如:subscription(訂閱),可以在這里訂閱 history 路由變化,進入根路徑執行 getChannelsAndGames
獲取數據,而不需要在 react 的生命周期中做這些事;用上 dva-loading 插件,在更改數據的過程中還會自動設置 loading 狀態,這在異步請求中非常有用!
dva官網:https://github.com/dvajs/dva/blob/master/README_zh-CN.md
mobx
既然 dva 這么好用,為什么還要使用 mobx 呢?還不是為了折騰😅,用了才能知道兩者的優劣,同樣的基於 mobx 我也創建了一個項目模版。
在使用 dva 的時候,但凡遇到異步請求的時候都需要先定義一個 effects ,請求完成后再觸發一個 action 去修改數據,於是,強迫症作怪,這兩者的命名總是讓我感覺難受和啰嗦,你可以看到我都是定義為 getXxx
和 getXxxSuccess
。
action 是修改 state 的唯一途徑,是的,所有的狀態管理庫都是這樣的,但是 mobx 通過一些工具函數解決了這一問題:
// app全局性狀態管理 import { observable, action, runInAction } from 'mobx'; import * as appApis from '../services/app'; export default class AppStore { @observable show = true; @observable list = []; @action toggleShow = () => { this.show = !this.show; } @action getData = async (params) => { try { const res = await appApis.getTopicsList(params); // await 之后,再次修改狀態需要動作: runInAction(() => { this.list = res.data; }); } catch (e) { console.error(e); } } } /** * ----------------------------------------------------------------- */ // app全局性狀態管理 import { observable, action } from 'mobx'; import { asyncAction } from "mobx-utils" import * as appApis from '../services/app'; export default class AppStore { @observable show = true; @observable list = []; @action toggleShow = () => { this.show = !this.show; } @asyncAction * getData(params) { // <- 注意*號,這是一個 generator 函數! try { const res = yield appApis.getTopicsList(params); // 用 yield 代替 await this.list = res.data; } catch (e) { console.error(e); } } }
以上是我最喜歡的兩種寫法,分別借助了 runInAction
和 asyncAction
這兩個工具函數,當然,還有其他方法可以參考。
mobx官網:http://cn.mobx.js.org/
總結
不管是 redux 、 dva ,還是 mobx ,每種技術的出現都是為了帶給我們更好的開發體驗、更高的開發效率,也伴隨着不一樣的學習成本,雖然 mobx 可以治好我的強迫症,但是也反逼我去學習了修飾器;雖然看起來 redux 是最繁瑣的,但是它可能是對新手最友好的,參考資料也是最多的,也能夠一步步讓我知道狀態是如何改變的,再者,如果我沒使用過 redux ,未必能體會到后兩者帶給我怎樣的便利之處。
還有這個UI組件工具也必不可少:
https://ant.design/docs/react/introduce-cn