大家好,最近有點忙,忙什么呢?忙着學習一個新的框架Redux,那么這個框架主要是用來做什么的,這篇博客暫時不做介紹,這篇博客針對有一定Redux開發基礎的人員,所以今天我講的重點是Redux里面很重要的一個方法-combineReducers(reducers)。
(一)官網介紹
首先,按照慣例,這個方法是什么,干什么用,輸入是什么,輸出是什么,這些都是我們要了解的,所以我們先來看看官網是如何介紹它的,在后面的內容中我會給大家分析一下這個方法內部是如何實現的以及它的實現原理,慢慢來,不要慌~
combineReducers(reducers)
這里為了方便大家閱讀,直接上中文解釋
隨着應用變得復雜,需要對 reducer 函數 進行拆分,拆分后的每一塊獨立負責管理 state 的一部分。
combineReducers 輔助函數的作用是,把一個由多個不同 reducer 函數作為 value 的 object,合並成一個最終的 reducer 函數,然后就可以對這個 reducer 調用 createStore。
合並后的 reducer 可以調用各個子 reducer,並把它們的結果合並成一個 state 對象。state 對象的結構由傳入的多個 reducer 的 key 決定。
最終,state 對象的結構會是這樣的:
{
reducer1: ...
reducer2: ...
}
通過為傳入對象的 reducer 命名不同來控制 state key 的命名。例如,你可以調用 combineReducers({ todos: myTodosReducer, counter: myCounterReducer }) 將 state 結構變為 { todos, counter }。
通常的做法是命名 reducer,然后 state 再去分割那些信息,因此你可以使用 ES6 的簡寫方法:combineReducers({ counter, todos })。這與 combineReducers({ counter: counter, todos: todos }) 一樣。
Flux 用戶使用須知
本函數可以幫助你組織多個 reducer,使它們分別管理自身相關聯的 state。類似於 Flux 中的多個 store 分別管理不同的 state。在 Redux 中,只有一個 store,但是 combineReducers 讓你擁有多個 reducer,同時保持各自負責邏輯塊的獨立性。
參數
reducers (Object): 一個對象,它的值(value) 對應不同的 reducer 函數,這些 reducer 函數后面會被合並成一個。下面會介紹傳入 reducer 函數需要滿足的規則。
之前的文檔曾建議使用 ES6 的 import * as reducers 語法來獲得 reducer 對象。這一點造成了很多疑問,因此現在建議在 reducers/index.js 里使用 combineReducers() 來對外輸出一個 reducer。下面有示例說明。
返回值
(Function):一個調用 reducers 對象里所有 reducer 的 reducer,並且構造一個與 reducers 對象結構相同的 state 對象。
注意
本函數設計的時候有點偏主觀,就是為了避免新手犯一些常見錯誤。也因些我們故意設定一些規則,但如果你自己手動編寫根 redcuer 時並不需要遵守這些規則。
每個傳入 combineReducers 的 reducer 都需滿足以下規則:
所有未匹配到的 action,必須把它接收到的第一個參數也就是那個 state 原封不動返回。
永遠不能返回 undefined。當過早 return 時非常容易犯這個錯誤,為了避免錯誤擴散,遇到這種情況時 combineReducers 會拋異常。
如果傳入的 state 就是 undefined,一定要返回對應 reducer 的初始 state。根據上一條規則,初始 state 禁止使用 undefined。使用 ES6 的默認參數值語法來設置初始 state 很容易,但你也可以手動檢查第一個參數是否為 undefined。
雖然 combineReducers 自動幫你檢查 reducer 是否符合以上規則,但你也應該牢記,並盡量遵守。
示例
//reducers/todos.js export default function todos(state = [], action) { switch (action.type) { case 'ADD_TODO': return state.concat([action.text]) default: return state } }
//reducers/counter.js export default function counter(state = 0, action) { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } }
//reducers/index.js import { combineReducers } from 'redux' import todos from './todos' import counter from './counter' export default combineReducers({ todos, counter })
//App.js import { createStore } from 'redux' import reducer from './reducers/index' let store = createStore(reducer) console.log(store.getState()) // { // counter: 0, // todos: [] // } store.dispatch({ type: 'ADD_TODO', text: 'Use Redux' }) console.log(store.getState()) // { // counter: 0, // todos: [ 'Use Redux' ] // }
小貼士
本方法只是起輔助作用!你可以自行實現不同功能的 combineReducers,甚至像實現其它函數一樣,明確地寫一個根 reducer 函數,用它把子 reducer 手動組裝成 state 對象。
在 reducer 層級的任何一級都可以調用 combineReducers。並不是一定要在最外層。實際上,你可以把一些復雜的子 reducer 拆分成單獨的孫子級 reducer,甚至更多層。
(二)內部分析
看了第一部分官網的介紹,大家都應該知道了它是如何使用的,但是作為開發人員,我覺得我們有必要思考一下它里面的究竟是如何實現的呢?下面我們來分析一下。
第一步,我們知道reducer 就是一個函數,接收舊的 state 和 action,返回新的 state。知道這點很重要!
第二步,我們來看combineReducers(reducers)方法,把一個由多個不同 reducer 函數作為 value 的 object,合並成一個最終的 reducer 函數,然后就可以對這個 reducer 調用 createStore。
那么combineReducers(reducers)返回的就是一個最終的reducer,reducer里面會返回新的state。下面我們結合代碼來看:
const rootReducer = combineReducers({
reducer1,
reducer2,
reducer3,
...
});
這里根reducer暫且起名為rootReducer,它就是通過combineReducers(reducers)返回的。那么combineReducers(reducers)是如何做的呢?
第三步,我們自己來寫一個function,來代替combineReducers(reducers)方法,從而來摸索內部是如何實現的,新建一個方法,如下:
var combineReducers1 = function(obj){ //內部具體代碼 }
這個方法返回的肯定是一個reducer,那么我們先寫出來:
var combineReducers1 = function(obj){ //內部具體代碼 //返回最終的reducer return reducer; }
我們應該能想到下一步該做什么了,既然返回一個reducer,那么我們就要創建一個reducer了,方法接收兩個參數,一個是state,一個是action,繼續:
var combineReducers1 = function(obj){ //內部具體代碼 function reducer(state,action){ //reducer具體邏輯 } //返回最終的reducer return reducer; }
reducer最終返回的是一個state,我們接着寫:
var combineReducers1 = function(obj){ //內部具體代碼 var finalState = {}; function reducer(state,action){ //reducer具體邏輯 //返回state return finalState; } //返回最終的reducer return reducer; }
那么現在想一想,我們傳入的object對象,實際上就是我們傳入的所有的reducer方法的集合,實際上里面做的就是分別調用每個reducer方法,將每個reducer方法作為value值賦予我們傳入object對象的屬性名,通過JavaScript遍歷對象獲取屬性名賦值的方法,我們可以得到最關鍵的代碼,接着往下寫:
var combineReducers1 = function(obj){ //內部具體代碼 var finalState = {}; function reducer(state,action){ //reducer具體邏輯 for (var p in obj) { //根據key屬性值調用function(state.屬性名,action) finalState[p] = obj[p](state[p], action); } //返回state return finalState; } //返回最終的reducer return reducer; }
因為我們reducer()方法里傳入的state,其實是根state,所以得根據屬性名來獲取對應的reducer上的state,到這里,關於combineReducers()方法的具體實現我們已經分析完了,了解了combineReducers是如何工作的,那么我們以后的工作才更好的展開,不至於出現了問題而不知道如何解決。
————————————————
版權聲明:本文為CSDN博主「胖子愛你520」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/woshizisezise/article/details/51142968