為了讓使用 redux 不再繁瑣,我發布了 @gxl/redux-model 來簡化 redux 使用

為了讓使用 redux 不再繁瑣,我發布了 @gxl/redux-model 來簡化 redux 使用

來自專欄 Make Possible

我們先來談談 redux 本身。其實作為一個狀態管理的解決方案,redux 本身非常簡單,action 觸發修改 reducer 來更新 state。但實際編寫起來卻很繁瑣。比如,現在我們把彈窗的打開關閉與否這個狀態放在了 redux 里。我們需要寫這麼一些東西:

const UPDATE_MODAL_STATE = UPDATE_MODAL_STATEconst updateModalState = open => ({ type: UPDATE_MODAL_STATE, payload: open }const updateModalStateReducer = (state, { type, payload }) => { if (type === UPDATE_MODAL_STATE) { return payload } return state}// 此處省略用 react-redux 對 actionCreator bind dispatch 和在 propTypes 裡面添加的 props 校驗

對比如果是使用 react setState

this.state = { modalOpen: false}... // React componentupdateModalState(open) { this.setState({ modalOpen: open })},...

很明顯可以看出來,代碼量立馬上來了。看到這兒,你也許會說為什麼不把 action 和 reducer 合併成一個東西。是的,前段時間看到一篇文章說要重新設計 redux,裡面就有這種做法,包括 dva 裡面也這麼做了。我想說,作為 redux,完全不應該把 action 和 reducer 耦合,因為一個 action 本來就是可能觸發不止一個 reducer。但話又說回來,整合在一起的確能解決實際使用中的很多場景,也能有效減少不少代碼。

然而,後來我試用了 dva 之後,很快就對它失望了。就只說兩點。第一,封裝的有點過了,它把 redux-saga, react-router 甚至連 redux 的 createStore 都封裝了,很不利於和現有項目結合。第二,文檔不齊全,既然你封裝的這麼狠,那總該很清楚的交代具體怎麼定製吧,沒有!後來我慢慢看它的源代碼才弄清楚了怎麼定製。

不過說到底,這種東西實現起來很簡單,於是就自己造了一個。

所以說這個輪子到底長啥樣

codesandbox 我寫了個例子

codesandbox.io/s/my241l

使用方法大致和 dva 類似,model 這麼定義

import { createModel } from "@gxl/redux-model";const model = createModel({ namespace: "home", state: { count: 0 }, watch: { count(val) { console.log("val changed", val); } }, // every computation corresponds to a pair of action creator and reducer // and you can call model[computation_name] to trigger the action // no need to manually bind action creators to dispatch computations: { updateCount(state, count) { return { ...state, count }; } }, // every effect corresponds to an action creator, when called via model[effect_name], // an action will be dispatched, and the effect will be triggered // and effects is handled by redux saga effects: { *updateCountAsync(count) { const num = yield service.updateCount(count); this.updateCount(num); } }});

computations 就是 action 和 reducer 的結合體,effects 就是 saga,另外還支持定義 actionCreators, reducer 和 saga,直接放在對應的 key 下面就可以。

自動綁定 actionCreators

actionCreators, effects, computations 裡面定義的方法都會被自動綁定到 dispatch,也就是說 model.updateCount 就可以 dispatch 這個 action 了,無需藉助 react-redux 的 connect。當然,也可以通過 model.actionCreators.updateCount 來獲取沒有綁定到 dispatch 的 action creator。

關於 action types

actionCreators, effects, computations 下面定義的 key 都會被轉化為 actionTypes 並可以通過 model.actionTypes 獲得。比如上面例子裡面的 updateCount 在 actionTypes 裡面就對應 UPDATECOUNT 裡面存儲的是 HOME/UPDATECOUNT 這樣的字元串。如果是 effects 會多出 _START 和 _END 結尾的 action type,方便在 saga 裡面使用 take。

新增兩個內置的 action creator

$set, 命名跟 vue 學的,以 $ 開頭表示這個方法是內置的,使用起來這樣 model.$set(path, value),會 dispatch 一個 HOME/SET 的 action path 對應 state 的路徑,value 是需要的值,這樣用起來簡直和 setState 一樣方便,而且還能享受到使用 redux 的各種好處。

$watch, 監聽一個 state 的變化。第一個參數是 state 的路徑,第二個是回調函數。這樣就可以不再依賴 componentWillReceiveProps 寫一堆繁瑣的代碼了。

關於 store

不像 dva,沒有對 createStore 做封裝。使用 extractReducer 提取出 reducer,feedStore 給 model 提供 store。非常易於和現有項目結合。

寫在最後

這個是繼 jellyweb,我造的另一個超級好用的輪子,再也不會覺得用 redux 做狀態管理是一件繁瑣的事。

GitHub 和 NPM 鏈接

gaoxiaoliangz/redux-model?

github.com圖標@gxl/redux-model?

www.npmjs.com圖標
推薦閱讀:

從單頁應用(SPA)到伺服器渲染(SSR)
瀏覽器指紋跨域共享
從process.versions了解Node.js的構成
記錄一次阿里、網易的前端面試經歷
[譯]手把手教你創建國際象棋 AI

TAG:Redux | 發布 | 前端開發 |