摘要:簡介中的能讓我們很方便地把多個組合起來,成為一個新的。正如官方文檔所說只是方便我們使用而已,我們可以自定義一個完全不同的來滿足我們特殊的需求。這個原則看著是很美好的,但在實際使用中還是會有一些例外的情況。
簡介
Redux 中的 combineReducers 能讓我們很方便地把多個 reducers 組合起來,成為一個新的 reducer。
然而,隨著我們的應用變得越來越復雜,combineReducers 有可能不能滿足我們的需求。
正如 Redux 官方文檔所說:
This helper is just a convenience! You can write your own combineReducers that works differently, or even assemble the state object from the child reducers manually and write a root reducing function explicitly, like you would write any other function.
combineReducers 只是方便我們使用而已,我們可以自定義一個完全不同的 combineReducers 來滿足我們特殊的需求。
原理我們先回憶一下 reducer 的寫法:
const reducer = (oldState, action) => newState;
reducer 是一個普通的函數,接受兩個參數:oldState 和 action,然后返回一個 newState。
為了把多個 reducers 組合起來,我們通常會用 Redux 自帶的 combineReducers 來實現:
const rootReducer = combineReducers({ key1: key1Reducer, key2: key2Reducer });
先留意一下我們傳了什么給 combineReducers:
{ key1: function(state.key1, action) { /*...*/ }, key2: function(state.key2, action) { /*...*/ }, }
好了,讓我們先來想一想,經過 combineReducers 的處理之后,我們得到了什么呢?
不用想了,很顯然我們得到了一個新的 reducer。
那這個新的 reducer 又長什么樣呢?
const rootReducer = (oldState, action) => newState;
你應該不會驚訝,因為所有 reducer 都長這個樣子,即使它是已經被組合過的 reducer,它也是長這個樣子。
現在你應該猜到 combineReducers 做了什么了吧?其實它最基本形態是這樣子的:
function combineReducers(reducers) { return function (state, action) { /*...*/ }; }
它接受 reducers 作為參數,然后返回一個標準的 reducer 函數。
注意:
其實到了這一步,我們就可以自定義 combineReducers 了,我們完全可以寫一個類似的函數,然后在里面寫各種 switch...case 語句來達到自定義的目的。
但我覺得我們還是先看看 Redux 自帶的 combineReducers 做了什么比較好,因為我們自定義的 combineReducers 很有可能需要原來的功能。
還記得我剛才叫你留意的地方嗎?沒錯,就是下面這個:
// reducers { key1: function(state.key1, action) { /*...*/ }, key2: function(state.key2, action) { /*...*/ } }
我們來回想一下 store.dispatch(action) 的過程:當一個 action 觸發的時候,所有 reducers 都應該響應這個 action,做出相應的改變,最后返回一個新的 store。
對著上面這個結構,我們其實很容易就能寫出這樣的效果,還能加上一些其他的處理:
function reCombineReducers(reducers) { return function (state, action) { switch (action.type) { case SP_ACTION: return Object.assign({}, state, { /* do something */ }); default: return Object.keys(reducers) .map(k => ({ [k]: reducers[k](state[k], action) })) .reduce((prev, next) => Object.assign({}, prev, next)); } } }
上面的例子模擬了原來 combineReducers 的功能,還對 SP_ACTION 進行了特殊的處理,很簡單吧!
然而,上面的例子雖然模擬了 combineReducers 的功能,但失去了 combineReducers 的檢查對象變化的功能,因為現在的 default block 中會返回一個全新的對象。
有沒有方法可以既保留 combineReducers 的全部功能,又能擴展它呢?
其實很簡單,我們只要利用 combineReducers 返回的函數就可以了!
(感謝 liximomo 指出上面例子中的缺陷)
function reCombineReducers(reducers) { let fn = combineReducers(reducers); return function (state, action) { switch (action.type) { case SP_ACTION: return Object.assign({}, state, { /* do something */ }); default: return fn(state, action); } } }實例
按照 Redux 的原則,不同的 reducer 應該相互獨立的,它們之間不應該有任何依賴。
這個原則看著是很美好的,但在實際使用中還是會有一些例外的情況。
一個很簡單的例子,也是我遇到過的例子,就是實現一個簡單的表格 (其實我的情況復雜的多,需要實現類似 Excel 那樣的操作,同時支持其他額外的功能)。
我們先來設計一下 state:
// state { rows: { ... }, cells: { ... }, data: { ... } }
rows, cells, data 都會響應一些特定的 action (如 CHANGE_ROW_PROPS, CHANGE_CELL_PROPS, CHANGE_DATA),做出相應的改變,這些都是我們所期望的。
然而,當出現一些特殊的 action (如 GET_TABLE_SUCCESS,表示成功從服務端獲取數據) 的時候,災難就出現了:
所有的 reducer 都需要監聽 GET_TABLE_SUCCESS 這個 action,這意味著如果我們有 n 個 reducer 的話,我們就需要修改 n 個文件!
當我再加上 UPDATE_TABLE_SUCCESS,REMOVE_TABLE_SUCCESS 之類的 action 時,我要再修改 n 個文件!
這不合理啊,為什么我加一個簡單的功能,需要修改這么多文件,最重要的是,這些修改都是非常類似!
這時候,我們就需要自定義 combineReducers 來解決我們的需求拉:
function reCombineReducers(reducers) { let fn = combineReducers(reducers); return function (state, action) { switch (action.type) { case GET_TABLE_SUCCESS: case UPDATE_TABLE_SUCCESS: return Object.assign({}, state, action.payload.table); case REMOVE_TABLE_SUCCESS: return initState; default: return fn(state, action); } } } const table = reCombineReducers({ sections, suites, rows, cells, toys, data, logics })
怎么樣,是不是比修改多個文件舒服很多?
(完)
出處http://scarletsky.github.io/2...
參考資料http://redux.js.org/docs/api/...
https://github.com/reactjs/re...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80096.html
摘要:再次將子返回的單個進行合并成一個新的完整的。此時發生了變化。如果不相同則調用觸發組件的更新,傳入組件,觸發組件的更新,此時組件獲得新的,的一次流程結束。 react-redux提供了connect和provider兩個好方式,provider將組件和redux關聯起來,將store傳給組件,組件通過dispatch發出action,store根據action的type屬性,調用對應的r...
摘要:只要輸入的值不變,每次輸出都是一樣的值。指定位置元素運算操作如可用以下方式代替主要是生成中最核心的對象。描述發生了什么,是響應并對進行更新。生成的對象包含個方法,分別為,和。按照約定,具有字段來表示它的類型。 前言: 一開始接觸redux的時候最令我記住的一句話是:You Might Not Need Redux(那我還寫這篇文章干嘛?手動滑稽) 回歸正題,本文主要是圍繞redux...
摘要:組件將元素作為結果返回。是把數據從項目傳到的有效載荷。有以下職責維持應用的提供方法獲取提供方法更新通過注冊監聽器通過返回的函數注銷監聽器。系列目錄前端大統一時代即將來臨項目實戰環境搭建項目實戰基本原理項目實戰登錄頁面編輯中 React相關 React 是一個采用聲明式,高效而且靈活的用來構建用戶界面的框架。 JSX 本質上來講,JSX 只是為React.createElement(co...
摘要:組件將元素作為結果返回。是把數據從項目傳到的有效載荷。有以下職責維持應用的提供方法獲取提供方法更新通過注冊監聽器通過返回的函數注銷監聽器。系列目錄前端大統一時代即將來臨項目實戰環境搭建項目實戰基本原理項目實戰登錄頁面編輯中 React相關 React 是一個采用聲明式,高效而且靈活的用來構建用戶界面的框架。 JSX 本質上來講,JSX 只是為React.createElement(co...
閱讀 1847·2021-11-22 15:25
閱讀 3912·2021-11-17 09:33
閱讀 2507·2021-10-12 10:12
閱讀 1802·2021-10-09 09:44
閱讀 3235·2021-10-08 10:04
閱讀 1313·2021-09-29 09:35
閱讀 1947·2019-08-30 12:57
閱讀 1303·2019-08-29 16:22