摘要:前言是一個非常實用的狀態管理庫,對于大多數使用庫的開發者來說,都是會接觸到的。在使用享受其帶來的便利的同時,我們也深受其問題的困擾。只支持同步,讓狀態可預測,方便測試。粗暴地級聯式刷新視圖使用優化。
前言
Redux是一個非常實用的狀態管理庫,對于大多數使用React庫的開發者來說,Redux都是會接觸到的。在使用Redux享受其帶來的便利的同時, 我們也深受其問題的困擾。
redux的問題之前在另外一篇文章Redux基礎中,就有提到以下這些問題
純凈。Redux只支持同步,讓狀態可預測,方便測試。 但不處理異步、副作用的情況,而把這個丟給了其他中間件,諸如redux-thunkredux-promiseredux-saga等等,選擇多也容易造成混亂~
啰嗦。那么寫過Redux的人,都知道actionreducer以及你的業務代碼非常啰嗦,模板代碼非常多。但是~,這也是為了讓數據的流動清晰明了。
性能。粗暴地、級聯式刷新視圖(使用react-redux優化)。
分型。原生 Redux-react 沒有分形結構,中心化 store
里面除了性能這一塊可以利用react-redux進行優化,其他的都是開發者不得不面對的問題,對于代碼有潔癖的人,啰嗦這一點確實是無法忍受的。
方案目標如果你使用過VUEX的話, 那么對于它的API肯定會相對喜歡很多,當然,vuex不是immutable,所以對于時間旅行這種業務不太友好。不過,我們可以自己實現一個具有vuex的簡潔語法和immutable屬性的redux-x(瞎命名)。
先看一下我們想要的目標是什么樣的?
首先, 我們再./models里面定義每個子state樹,里面帶有namespace、state、reducers、effects等屬性, 如下:
export default { // 命名空間 namespace: "common", // 初始化state state: { loading: false, }, // reducers 同步更新 類似于vuex的mutations reducers: { updateLoadingStatus(state, action) { return { ...state, loading: action.payload } }, }, // reducers 異步更新 類似于vuex的actions efffects: { someEffect(action, store) { // some effect code ... ... // 將結果返回 return result } } }
通過上面的實現,我們基本解決了Redux本身的一些瑕疵
1.在effects中存放的方法用于解決不支持異步、副作用的問題 2.通過合并reducer和action, 將模板代碼大大減少 3.具有分型結構(namespace),并且中心化處理如何實現 暴露的接口redux-x
首先,我們只是在外層封裝了一層API方便使用,那么說到底,傳給redux的combineReducers還是一個redux對象。另外一個則是要處理副作用的話,那就必須使用到了中間件,所以最后我們暴露出來的函數的返回值應該具有上面兩個屬性,如下:
import reduxSimp from "../utils/redux-simp" // 內部實現 import common from "./common" // models文件下common的狀態管理 import user from "./user" // models文件下user的狀態管理 import rank from "./rank" // models文件下rank的狀態管理 const reduxX = reduxSimp({ common, user, rank }) export default reduxX
const store = createStore( combineReducers(reduxX.reducers), // reducers樹 {}, applyMiddleware(reduxX.effectMiddler) // 處理副作用中間件 )
第一步, 我們先實現一個暴露出來的函數reduxSimp,通過他對model里面各個屬性進行加工,大概的代碼如下:
const reductionReducer = function() { // somecode } const reductionEffects = function() { // somecode } const effectMiddler = function() { // somecode } /** * @param {Object} models */ const simplifyRedux = (models) => { // 初始化一個reducers 最后傳給combinReducer的值 也是最終還原的redux const reducers = {} // 遍歷傳入的model const modelArr = Object.keys(models) modelArr.forEach((key) => { const model = models[key] // 還原effect reductionEffects(model) // 還原reducer,同時通過namespace屬性處理命名空間 const reducer = reductionReducer(model) reducers[model.namespace] = reducer }) // 返回一個reducers和一個專門處理副作用的中間件 return { reducers, effectMiddler } }還原effects
對于effects, 使用的時候如下(沒什么區別):
props.dispatch({ type: "rank/fundRankingList_fetch", payload: { fundType: props.fundType, returnType: props.returnType, pageNo: fund.pageNo, pageSize: 20 } })
還原effects的思路大概就是先將每一個model下的effect收集起來,同時加上命名空間作為前綴,將副作用的key即type 和相對應的方法value分開存放在兩個數組里面,然后定義一個中間件,每當有一個dispatch的時候,檢查key數組中是否有符合的key,如果有,則調用對應的value數組里面的方法。
// 常量 分別存放副作用的key即type 和相對應的方法 const effectsKey = [] const effectsMethodArr = [] /** * 還原effects的函數 * @param {Object} model */ const reductionEffects = (model) => { const { namespace, effects } = model const effectsArr = Object.keys(effects || {}) effectsArr.forEach((effect) => { // 存放對應effect的type和方法 effectsKey.push(namespace + "/" + effect) effectsMethodArr.push(model.effects[effect]) }) } /** * 處理effect的中間件 具體參考redux中間件 * @param {Object} store */ const effectMiddler = store => next => (action) => { next(action) // 如果存在對應的effect, 調用其方法 const index = effectsKey.indexOf(action.type) if (index > -1) { return effectsMethodArr[index](action, store) } return action }還原reducers
reducers的應用也是和原來沒有區別:
props.dispatch({ type: "common/updateLoadingStatus", payload: true })
代碼實現的思路就是最后返回一個函數,也就是我們通常寫的redux函數,函數內部遍歷對應命名空間的reducer,找到匹配的reducer執行后返回結果
/** * 還原reducer的函數 * @param {Object} model 傳入的model對象 */ const reductionReducer = (model) => { const { namespace, reducers } = model const initState = model.state const reducerArr = Object.keys(reducers || {}) // 該函數即redux函數 return (state = initState, action) => { let result = state reducerArr.forEach((reducer) => { // 返回匹配的action if (action.type === `${namespace}/${reducer}`) { result = model.reducers[reducer](state, action) } }) return result } }最終代碼
最終的代碼如下,加上了一些錯誤判斷:
// 常量 分別存放副作用的key即type 和相對應的方法 const effectsKey = [] const effectsMethodArr = [] /** * 還原reducer的函數 * @param {Object} model 傳入的model對象 */ const reductionReducer = (model) => { if (typeof model !== "object") { throw Error("Model must be object!") } const { namespace, reducers } = model if (!namespace || typeof namespace !== "string") { throw Error(`The namespace must be a defined and non-empty string! It is ${namespace}`) } const initState = model.state const reducerArr = Object.keys(reducers || {}) reducerArr.forEach((reducer) => { if (typeof model.reducers[reducer] !== "function") { throw Error(`The reducer must be a function! In ${namespace}`) } }) // 該函數即redux函數 return (state = initState, action) => { let result = state reducerArr.forEach((reducer) => { // 返回匹配的action if (action.type === `${namespace}/${reducer}`) { result = model.reducers[reducer](state, action) } }) return result } } /** * 還原effects的函數 * @param {Object} model */ const reductionEffects = (model) => { const { namespace, effects } = model const effectsArr = Object.keys(effects || {}) effectsArr.forEach((effect) => { if (typeof model.effects[effect] !== "function") { throw Error(`The effect must be a function! In ${namespace}`) } }) effectsArr.forEach((effect) => { // 存放對應effect的type和方法 effectsKey.push(namespace + "/" + effect) effectsMethodArr.push(model.effects[effect]) }) } /** * 處理effect的中間件 具體參考redux中間件 * @param {Object} store */ const effectMiddler = store => next => (action) => { next(action) // 如果存在對應的effect, 調用其方法 const index = effectsKey.indexOf(action.type) if (index > -1) { return effectsMethodArr[index](action, store) } return action } /** * @param {Object} models */ const simplifyRedux = (models) => { if (typeof models !== "object") { throw Error("Models must be object!") } // 初始化一個reducers 最后傳給combinReducer的值 也是最終還原的redux const reducers = {} // 遍歷傳入的model const modelArr = Object.keys(models) modelArr.forEach((key) => { const model = models[key] // 還原effect reductionEffects(model) // 還原reducer,同時通過namespace屬性處理命名空間 const reducer = reductionReducer(model) reducers[model.namespace] = reducer }) // 返回一個reducers和一個專門處理副作用的中間件 return { reducers, effectMiddler } } export default simplifyRedux思考
如何結合Immutable.js使用?
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101587.html
摘要:也就是說不應該有公開的,所有都應該是私有的,只能有公開的。允許使用方法設置監聽函數,一旦發生變化,就自動執行這個函數。用一個叫做的純函數來處理事件。可以通過得到當前狀態。在中,同步的表現就是發出以后,立即算出。 這篇文章試著聊明白這一堆看起來挺復雜的東西。在聊之前,大家要始終記得一句話:一切前端概念,都是紙老虎。 不管是Vue,還是 React,都需要管理狀態(state),比如組件之...
摘要:原文地址前言筆者最近在學習使用,提到就繞不過去。同時應當注意,當組件時應當重新收集依賴,因為之后依賴關系很可能已經變化了清空依賴至此,我們的小目標已經完成了,在中使用不再是夢 原文地址 前言 筆者最近在學習使用react,提到react就繞不過去redux。redux是一個狀態管理架構,被廣泛用于react項目中,但是redux并不是專為react而生,兩者還需要react-redux...
簡介:簡單實現react-redux基礎api react-redux api回顧 把store放在context里,所有子組件可以直接拿到store數據 使組件層級中的 connect() 方法都能夠獲得 Redux store 根組件應該嵌套在 中 ReactDOM.render( , rootEl ) ReactDOM.render( ...
摘要:簡介創建的函數,返回一個對象,包含等方法合并多個中間件處理,在實際的前調用一系列中間件,類似于綁定和函數式編程中常見的方法,介紹官方提供的綁定庫。 前言 在學習了React之后, 緊跟著而來的就是Redux了~ 在系統性的學習一個東西的時候, 了解其背景、設計以及解決了什么問題都是非常必要的。接下來記錄的是, 我個人在學習Redux時的一些雜七雜八~ Redux是什么 通俗理解 h...
摘要:的優勢保證不可變每次通過操作的對象都會返回一個新的對象豐富的性能好通過字典樹對數據結構的共享的問題與原生交互不友好通過生成的對象在操作上與原生不同,如訪問屬性,。 Immutable.js Immutable的優勢 1. 保證不可變(每次通過Immutable.js操作的對象都會返回一個新的對象) 2. 豐富的API 3. 性能好 (通過字典樹對數據結構的共享) Immutab...
閱讀 1759·2021-11-11 16:55
閱讀 2545·2021-08-27 13:11
閱讀 3622·2019-08-30 15:53
閱讀 2301·2019-08-30 15:44
閱讀 1378·2019-08-30 11:20
閱讀 1036·2019-08-30 10:55
閱讀 943·2019-08-29 18:40
閱讀 3029·2019-08-29 16:13