createStore(reducer, [initialState],enhancer)
創(chuàng)建一個(gè) Redux store來(lái)以存放應(yīng)用中所有的 state。應(yīng)用中應(yīng)有且僅有一個(gè) store。
參數(shù)
reducer
(Function): 接收兩個(gè)參數(shù),分別是當(dāng)前的 state 樹(shù)和要處理的 action,返回新的 state 樹(shù)。
initialState
(any): 初始時(shí)的 state。 在同構(gòu)應(yīng)用中,你可以決定是否把服務(wù)端傳來(lái)的 state 水合(hydrate)后傳給它,或者從之前保存的用戶會(huì)話中恢復(fù)一個(gè)傳給它。如果你使用 combineReducers創(chuàng)建 reducer
,它必須是一個(gè)普通對(duì)象,與傳入的 keys 保持同樣的結(jié)構(gòu)。否則,你可以自由傳入任何 reducer
可理解的內(nèi)容。
enhancer
(Function): Store enhancer 是一個(gè)組合 store creator 的高階函數(shù),返回一個(gè)新的強(qiáng)化過(guò)的 store creator。這與 middleware 相似,它也允許你通過(guò)復(fù)合函數(shù)改變 store 接口。
返回值
( Store ): 保存了應(yīng)用所有 state 的對(duì)象。改變 state 的惟一方法是 dispatchaction。你也可以 subscribe 監(jiān)聽(tīng)state 的變化,然后更新 UI。
小貼士
應(yīng)用中不要?jiǎng)?chuàng)建多個(gè) store!相反,使用 combineReducers 來(lái)把多個(gè) reducer 創(chuàng)建成一個(gè)根 reducer。
你可以決定 state 的格式。你可以使用普通對(duì)象或者 Immutable 這類(lèi)的實(shí)現(xiàn)。如果你不知道如何做,剛開(kāi)始可以使用普通對(duì)象。
如果 state 是普通對(duì)象,永遠(yuǎn)不要修改它!比如,reducer 里不要使用 Object.assign(state, newData),應(yīng)該使用 Object.assign({}, state, newData)。這樣才不會(huì)覆蓋舊的 state。也可以使用 Babel 階段 1 中的 ES7 對(duì)象的 spread 操作 特性中的 return { ...state, ...newData }。
對(duì)于服務(wù)端運(yùn)行的同構(gòu)應(yīng)用,為每一個(gè)請(qǐng)求創(chuàng)建一個(gè) store 實(shí)例,以此讓 store 相隔離。dispatch 一系列請(qǐng)求數(shù)據(jù)的 action 到 store 實(shí)例上,等待請(qǐng)求完成后再在服務(wù)端渲染應(yīng)用。
當(dāng) store 創(chuàng)建后,Redux 會(huì) dispatch 一個(gè) action 到 reducer 上,來(lái)用初始的 state 來(lái)填充 store。你不需要處理這個(gè) action。但要記住,如果第一個(gè)參數(shù)也就是傳入的 state 如果是 undefined 的話,reducer 應(yīng)該返回初始的 state 值。
Store
Store 就是用來(lái)維持應(yīng)用所有的 state 樹(shù) 的一個(gè)對(duì)象。 改變 store 內(nèi) state 的惟一途徑是對(duì)它 dispatch 一個(gè) action。
Store 不是類(lèi)。它只是有幾個(gè)方法的對(duì)象。 要?jiǎng)?chuàng)建它,只需要把根部的 reducing 函數(shù) 傳遞給 createStore
Store 方法
getState()
dispatch(action)
subscribe(listener)
replaceReducer(nextReducer)
Store 方法
getState()
返回應(yīng)用當(dāng)前的 state 樹(shù)。
它與 store 的最后一個(gè) reducer 返回值相同。
返回值
(any): 應(yīng)用當(dāng)前的 state 樹(shù)。
dispatch(action)
分發(fā) action。這是觸發(fā) state 變化的惟一途徑。
會(huì)使用當(dāng)前 getState() 的結(jié)果和傳入的 action 以同步方式的調(diào)用 store 的 reduce 函數(shù)。返回值會(huì)被作為下一個(gè) state。從現(xiàn)在開(kāi)始,這就成為了 getState() 的返回值,同時(shí)變化監(jiān)聽(tīng)器(change listener)會(huì)被觸發(fā)。
參數(shù)
action (Object): 描述應(yīng)用變化的普通對(duì)象。Action 是把數(shù)據(jù)傳入 store 的惟一途徑,所以任何數(shù)據(jù),無(wú)論來(lái)自 UI 事件,網(wǎng)絡(luò)回調(diào)或者是其它資源如 WebSockets,最終都應(yīng)該以 action 的形式被 dispatch。按照約定,action 具有 type 字段來(lái)表示它的類(lèi)型。type 也可被定義為常量或者是從其它模塊引入。最好使用字符串,而不是 Symbols 作為 action,因?yàn)樽址强梢员恍蛄谢摹3?type 字段外,action 對(duì)象的結(jié)構(gòu)完全取決于你。參照 Flux 標(biāo)準(zhǔn) Action 獲取如何組織 action 的建議。
返回值
(Object): 要 dispatch 的 action。
subscribe(listener)
添加一個(gè)變化監(jiān)聽(tīng)器。每當(dāng) dispatch action 的時(shí)候就會(huì)執(zhí)行,state 樹(shù)中的一部分可能已經(jīng)變化。你可以在回調(diào)函數(shù)里調(diào)用 getState() 來(lái)拿到當(dāng)前 state。
這是一個(gè)底層 API。多數(shù)情況下,你不會(huì)直接使用它,會(huì)使用一些 React(或其它庫(kù))的綁定。如果你想讓回調(diào)函數(shù)執(zhí)行的時(shí)候使用當(dāng)前的 state,你可以 把 store 轉(zhuǎn)換成一個(gè) Observable 或者寫(xiě)一個(gè)定制的 observeStore 工具。
如果需要解綁這個(gè)變化監(jiān)聽(tīng)器,執(zhí)行 subscribe 返回的函數(shù)即可。
參數(shù)
listener (Function): 每當(dāng) dispatch action 的時(shí)候都會(huì)執(zhí)行的回調(diào)。state 樹(shù)中的一部分可能已經(jīng)變化。你可以在回調(diào)函數(shù)里調(diào)用 getState() 來(lái)拿到當(dāng)前 state。store 的 reducer 應(yīng)該是純函數(shù),因此你可能需要對(duì) state 樹(shù)中的引用做深度比較來(lái)確定它的值是否有變化。
返回值
(Function): 一個(gè)可以解綁變化監(jiān)聽(tīng)器的函數(shù)。
replaceReducer(nextReducer)
替換 store 當(dāng)前用來(lái)計(jì)算 state 的 reducer。
這是一個(gè)高級(jí) API。只有在你需要實(shí)現(xiàn)代碼分隔,而且需要立即加載一些 reducer 的時(shí)候才可能會(huì)用到它。在實(shí)現(xiàn) Redux 熱加載機(jī)制的時(shí)候也可能會(huì)用到。
參數(shù)
reducer (Function) store 會(huì)使用的下一個(gè) reducer。
combineReducers(reducers)
隨著應(yīng)用變得復(fù)雜,需要對(duì) reducer 函數(shù) 進(jìn)行拆分,拆分后的每一塊獨(dú)立負(fù)責(zé)管理 state 的一部分。
combineReducers 輔助函數(shù)的作用是,把一個(gè)由多個(gè)不同 reducer 函數(shù)作為 value 的 object,合并成一個(gè)最終的 reducer 函數(shù),然后就可以對(duì)這個(gè) reducer 調(diào)用 createStore。
合并后的 reducer 可以調(diào)用各個(gè)子 reducer,并把它們的結(jié)果合并成一個(gè) state 對(duì)象。state 對(duì)象的結(jié)構(gòu)由傳入的多個(gè) reducer 的 key 決定。
最終,state 對(duì)象的結(jié)構(gòu)會(huì)是這樣的:
{
reducer1: ...
reducer2: ...
}
通過(guò)為傳入對(duì)象的 reducer 命名不同來(lái)控制 state key 的命名。例如,你可以調(diào)用 combineReducers({ todos: myTodosReducer, counter: myCounterReducer }) 將 state 結(jié)構(gòu)變?yōu)?{ todos, counter }。
通常的做法是命名 reducer,然后 state 再去分割那些信息,因此你可以使用 ES6 的簡(jiǎn)寫(xiě)方法:combineReducers({ counter, todos })。這與 combineReducers({ counter: counter, todos: todos }) 一樣。
參數(shù)
reducers (Object): 一個(gè)對(duì)象,它的值(value) 對(duì)應(yīng)不同的 reducer 函數(shù),這些 reducer 函數(shù)后面會(huì)被合并成一個(gè)。下面會(huì)介紹傳入 reducer 函數(shù)需要滿足的規(guī)則。
之前的文檔曾建議使用 ES6 的 import * as reducers 語(yǔ)法來(lái)獲得 reducer 對(duì)象。這一點(diǎn)造成了很多疑問(wèn),因此現(xiàn)在建議在 reducers/index.js 里使用 combineReducers() 來(lái)對(duì)外輸出一個(gè) reducer。下面有示例說(shuō)明。
返回值
(Function):一個(gè)調(diào)用 reducers 對(duì)象里所有 reducer 的 reducer,并且構(gòu)造一個(gè)與 reducers 對(duì)象結(jié)構(gòu)相同的 state 對(duì)象。
注意
本函數(shù)設(shè)計(jì)的時(shí)候有點(diǎn)偏主觀,就是為了避免新手犯一些常見(jiàn)錯(cuò)誤。也因些我們故意設(shè)定一些規(guī)則,但如果你自己手動(dòng)編寫(xiě)根 redcuer 時(shí)并不需要遵守這些規(guī)則。
每個(gè)傳入 combineReducers 的 reducer 都需滿足以下規(guī)則:
所有未匹配到的 action,必須把它接收到的第一個(gè)參數(shù)也就是那個(gè) state 原封不動(dòng)返回。
永遠(yuǎn)不能返回 undefined。當(dāng)過(guò)早 return 時(shí)非常容易犯這個(gè)錯(cuò)誤,為了避免錯(cuò)誤擴(kuò)散,遇到這種情況時(shí) combineReducers 會(huì)拋異常。
如果傳入的 state 就是 undefined,一定要返回對(duì)應(yīng) reducer 的初始 state。根據(jù)上一條規(guī)則,初始 state 禁止使用 undefined。使用 ES6 的默認(rèn)參數(shù)值語(yǔ)法來(lái)設(shè)置初始 state 很容易,但你也可以手動(dòng)檢查第一個(gè)參數(shù)是否為 undefined。
雖然 combineReducers 自動(dòng)幫你檢查 reducer 是否符合以上規(guī)則,但你也應(yīng)該牢記,并盡量遵守。
小貼士
本方法只是起輔助作用!你可以自行實(shí)現(xiàn)不同功能的 combineReducers,甚至像實(shí)現(xiàn)其它函數(shù)一樣,明確地寫(xiě)一個(gè)根 reducer 函數(shù),用它把子 reducer 手動(dòng)組裝成 state 對(duì)象。
在 reducer 層級(jí)的任何一級(jí)都可以調(diào)用 combineReducers。并不是一定要在最外層。實(shí)際上,你可以把一些復(fù)雜的子 reducer 拆分成單獨(dú)的孫子級(jí) reducer,甚至更多層。