createStore(reducer, [initialState],enhancer)
創(chuàng)建一個 Redux store來以存放應(yīng)用中所有的 state核无。應(yīng)用中應(yīng)有且僅有一個 store。
參數(shù)
reducer
(Function): 接收兩個參數(shù)藕坯,分別是當(dāng)前的 state 樹和要處理的 action团南,返回新的 state 樹噪沙。
initialState
(any): 初始時的 state。 在同構(gòu)應(yīng)用中已慢,你可以決定是否把服務(wù)端傳來的 state 水合(hydrate)后傳給它曲聂,或者從之前保存的用戶會話中恢復(fù)一個傳給它霹购。如果你使用 combineReducers創(chuàng)建 reducer
佑惠,它必須是一個普通對象,與傳入的 keys 保持同樣的結(jié)構(gòu)齐疙。否則膜楷,你可以自由傳入任何 reducer
可理解的內(nèi)容。
enhancer
(Function): Store enhancer 是一個組合 store creator 的高階函數(shù)贞奋,返回一個新的強化過的 store creator赌厅。這與 middleware 相似,它也允許你通過復(fù)合函數(shù)改變 store 接口轿塔。
返回值
( Store ): 保存了應(yīng)用所有 state 的對象特愿。改變 state 的惟一方法是 dispatchaction。你也可以 subscribe 監(jiān)聽state 的變化勾缭,然后更新 UI揍障。
小貼士
應(yīng)用中不要創(chuàng)建多個 store!相反俩由,使用 combineReducers 來把多個 reducer 創(chuàng)建成一個根 reducer毒嫡。
你可以決定 state 的格式。你可以使用普通對象或者 Immutable 這類的實現(xiàn)幻梯。如果你不知道如何做兜畸,剛開始可以使用普通對象。
如果 state 是普通對象碘梢,永遠(yuǎn)不要修改它咬摇!比如,reducer 里不要使用 Object.assign(state, newData)煞躬,應(yīng)該使用 Object.assign({}, state, newData)菲嘴。這樣才不會覆蓋舊的 state。也可以使用 Babel 階段 1 中的 ES7 對象的 spread 操作 特性中的 return { ...state, ...newData }汰翠。
對于服務(wù)端運行的同構(gòu)應(yīng)用龄坪,為每一個請求創(chuàng)建一個 store 實例,以此讓 store 相隔離复唤。dispatch 一系列請求數(shù)據(jù)的 action 到 store 實例上健田,等待請求完成后再在服務(wù)端渲染應(yīng)用。
當(dāng) store 創(chuàng)建后佛纫,Redux 會 dispatch 一個 action 到 reducer 上妓局,來用初始的 state 來填充 store总放。你不需要處理這個 action。但要記住好爬,如果第一個參數(shù)也就是傳入的 state 如果是 undefined 的話局雄,reducer 應(yīng)該返回初始的 state 值。
Store
Store 就是用來維持應(yīng)用所有的 state 樹 的一個對象存炮。 改變 store 內(nèi) state 的惟一途徑是對它 dispatch 一個 action炬搭。
Store 不是類。它只是有幾個方法的對象穆桂。 要創(chuàng)建它宫盔,只需要把根部的 reducing 函數(shù) 傳遞給 createStore
Store 方法
getState()
dispatch(action)
subscribe(listener)
replaceReducer(nextReducer)
Store 方法
getState()
返回應(yīng)用當(dāng)前的 state 樹。
它與 store 的最后一個 reducer 返回值相同享完。
返回值
(any): 應(yīng)用當(dāng)前的 state 樹灼芭。
dispatch(action)
分發(fā) action。這是觸發(fā) state 變化的惟一途徑般又。
會使用當(dāng)前 getState() 的結(jié)果和傳入的 action 以同步方式的調(diào)用 store 的 reduce 函數(shù)彼绷。返回值會被作為下一個 state。從現(xiàn)在開始茴迁,這就成為了 getState() 的返回值寄悯,同時變化監(jiān)聽器(change listener)會被觸發(fā)。
參數(shù)
action (Object): 描述應(yīng)用變化的普通對象笋熬。Action 是把數(shù)據(jù)傳入 store 的惟一途徑热某,所以任何數(shù)據(jù),無論來自 UI 事件胳螟,網(wǎng)絡(luò)回調(diào)或者是其它資源如 WebSockets昔馋,最終都應(yīng)該以 action 的形式被 dispatch。按照約定糖耸,action 具有 type 字段來表示它的類型秘遏。type 也可被定義為常量或者是從其它模塊引入。最好使用字符串嘉竟,而不是 Symbols 作為 action邦危,因為字符串是可以被序列化的。除了 type 字段外舍扰,action 對象的結(jié)構(gòu)完全取決于你倦蚪。參照 Flux 標(biāo)準(zhǔn) Action 獲取如何組織 action 的建議。
返回值
(Object): 要 dispatch 的 action边苹。
subscribe(listener)
添加一個變化監(jiān)聽器陵且。每當(dāng) dispatch action 的時候就會執(zhí)行,state 樹中的一部分可能已經(jīng)變化个束。你可以在回調(diào)函數(shù)里調(diào)用 getState() 來拿到當(dāng)前 state慕购。
這是一個底層 API聊疲。多數(shù)情況下,你不會直接使用它沪悲,會使用一些 React(或其它庫)的綁定获洲。如果你想讓回調(diào)函數(shù)執(zhí)行的時候使用當(dāng)前的 state,你可以 把 store 轉(zhuǎn)換成一個 Observable 或者寫一個定制的 observeStore 工具殿如。
如果需要解綁這個變化監(jiān)聽器贡珊,執(zhí)行 subscribe 返回的函數(shù)即可。
參數(shù)
listener (Function): 每當(dāng) dispatch action 的時候都會執(zhí)行的回調(diào)握截。state 樹中的一部分可能已經(jīng)變化飞崖。你可以在回調(diào)函數(shù)里調(diào)用 getState() 來拿到當(dāng)前 state烂叔。store 的 reducer 應(yīng)該是純函數(shù)谨胞,因此你可能需要對 state 樹中的引用做深度比較來確定它的值是否有變化。
返回值
(Function): 一個可以解綁變化監(jiān)聽器的函數(shù)蒜鸡。
replaceReducer(nextReducer)
替換 store 當(dāng)前用來計算 state 的 reducer胯努。
這是一個高級 API。只有在你需要實現(xiàn)代碼分隔逢防,而且需要立即加載一些 reducer 的時候才可能會用到它叶沛。在實現(xiàn) Redux 熱加載機制的時候也可能會用到。
參數(shù)
reducer (Function) store 會使用的下一個 reducer忘朝。
combineReducers(reducers)
隨著應(yīng)用變得復(fù)雜灰署,需要對 reducer 函數(shù) 進行拆分,拆分后的每一塊獨立負(fù)責(zé)管理 state 的一部分局嘁。
combineReducers 輔助函數(shù)的作用是溉箕,把一個由多個不同 reducer 函數(shù)作為 value 的 object,合并成一個最終的 reducer 函數(shù)悦昵,然后就可以對這個 reducer 調(diào)用 createStore肴茄。
合并后的 reducer 可以調(diào)用各個子 reducer,并把它們的結(jié)果合并成一個 state 對象但指。state 對象的結(jié)構(gòu)由傳入的多個 reducer 的 key 決定寡痰。
最終,state 對象的結(jié)構(gòu)會是這樣的:
{
reducer1: ...
reducer2: ...
}
通過為傳入對象的 reducer 命名不同來控制 state key 的命名棋凳。例如拦坠,你可以調(diào)用 combineReducers({ todos: myTodosReducer, counter: myCounterReducer }) 將 state 結(jié)構(gòu)變?yōu)?{ todos, counter }。
通常的做法是命名 reducer剩岳,然后 state 再去分割那些信息贞滨,因此你可以使用 ES6 的簡寫方法:combineReducers({ counter, todos })。這與 combineReducers({ counter: counter, todos: todos }) 一樣卢肃。
參數(shù)
reducers (Object): 一個對象疲迂,它的值(value) 對應(yīng)不同的 reducer 函數(shù)才顿,這些 reducer 函數(shù)后面會被合并成一個。下面會介紹傳入 reducer 函數(shù)需要滿足的規(guī)則尤蒿。
之前的文檔曾建議使用 ES6 的 import * as reducers 語法來獲得 reducer 對象郑气。這一點造成了很多疑問,因此現(xiàn)在建議在 reducers/index.js 里使用 combineReducers() 來對外輸出一個 reducer腰池。下面有示例說明尾组。
返回值
(Function):一個調(diào)用 reducers 對象里所有 reducer 的 reducer,并且構(gòu)造一個與 reducers 對象結(jié)構(gòu)相同的 state 對象示弓。
注意
本函數(shù)設(shè)計的時候有點偏主觀讳侨,就是為了避免新手犯一些常見錯誤。也因些我們故意設(shè)定一些規(guī)則奏属,但如果你自己手動編寫根 redcuer 時并不需要遵守這些規(guī)則跨跨。
每個傳入 combineReducers 的 reducer 都需滿足以下規(guī)則:
所有未匹配到的 action,必須把它接收到的第一個參數(shù)也就是那個 state 原封不動返回囱皿。
永遠(yuǎn)不能返回 undefined勇婴。當(dāng)過早 return 時非常容易犯這個錯誤,為了避免錯誤擴散嘱腥,遇到這種情況時 combineReducers 會拋異常耕渴。
如果傳入的 state 就是 undefined,一定要返回對應(yīng) reducer 的初始 state齿兔。根據(jù)上一條規(guī)則橱脸,初始 state 禁止使用 undefined。使用 ES6 的默認(rèn)參數(shù)值語法來設(shè)置初始 state 很容易分苇,但你也可以手動檢查第一個參數(shù)是否為 undefined添诉。
雖然 combineReducers 自動幫你檢查 reducer 是否符合以上規(guī)則,但你也應(yīng)該牢記组砚,并盡量遵守吻商。
小貼士
本方法只是起輔助作用!你可以自行實現(xiàn)不同功能的 combineReducers糟红,甚至像實現(xiàn)其它函數(shù)一樣艾帐,明確地寫一個根 reducer 函數(shù),用它把子 reducer 手動組裝成 state 對象盆偿。
在 reducer 層級的任何一級都可以調(diào)用 combineReducers柒爸。并不是一定要在最外層。實際上事扭,你可以把一些復(fù)雜的子 reducer 拆分成單獨的孫子級 reducer捎稚,甚至更多層。