# 先前技術
Redux 是一個混合產物。它和一些設計模式及技術相似,但也有不同之處。讓我們來探索一下這些相似與不同。
### Flux
Redux 的靈感來源于 [Flux](https://facebook.github.io/flux/) 的幾個重要特性。和 Flux 一樣,Redux 規定,將模型的更新邏輯全部集中于一個特定的層(Flux 里的 store,Redux 里的 reducer)。Flux 和 Redux 都不允許程序直接修改數據,而是用一個叫作 “action” 的普通對象來對更改進行描述。
而不同于 Flux ,**Redux 并沒有 dispatcher 的概念**。原因是它依賴純函數來替代事件處理器。純函數構建簡單,也不需額外的實體來管理它們。你可以將這點看作這兩個框架的差異或細節實現,取決于你怎么看 Flux。Flux 常常[被表述為 `(state, action) => state`](https://speakerdeck.com/jmorrell/jsconf-uy-flux-those-who-forget-the-past-dot-dot-dot)。從這個意義上說,Redux 無疑是 Flux 架構的實現,且得益于純函數而更為簡單。
和 Flux 的另一個重要區別,是 **Redux 設想你永遠不會變動你的數據**。你可以很好地使用普通對象和數組來管理 state ,而不是在多個 reducer 里變動數據。正確且簡便的方式是,你應該在 reducer 中返回一個新對象來更新 state, 同時配合 [object spread 運算符提案](../recipes/UsingObjectSpreadOperator.md) 或一些庫,如 [Immutable](https://facebook.github.io/immutable-js)。
雖然出于性能方面的考慮,[寫不純的 reducer](https://github.com/reduxjs/redux/issues/328#issuecomment-125035516) 來變動數據在技術上是**可行**的,但我們并不鼓勵這么做。不純的 reducer 會使一些開發特性,如時間旅行、記錄/回放或熱加載不可實現。此外,在大部分實際應用中,這種數據不可變動的特性并不會帶來性能問題,就像 [Om](https://github.com/omcljs/om) 所表現的,即使對象分配失敗,仍可以防止昂貴的重渲染和重計算。而得益于 reducer 的純度,應用內的變化更是一目了然。
### Elm
[Elm](http://elm-lang.org/) 是一種函數式編程語言,由 [Evan Czaplicki](https://twitter.com/czaplic) 受 Haskell 語言的啟發開發。它執行一種 [“model view update” 的架構](http://elm-lang.org/guide/architecture) ,更新遵循 `(state, action) => state` 的規則。 Elm 的 “updater” 與 Redux 里的 reducer 服務于相同的目的。
不同于 Redux,Elm 是一門語言,因此它在執行純度,靜態類型,不可變動性,action 和模式匹配等方面更具優勢。即使你不打算使用 Elm,也可以讀一讀 Elm 的架構,嘗試一把。基于此,有一個有趣的[使用 JavaScript 庫實現類似想法](https://github.com/paldepind/noname-functional-frontend-framework) 的項目。Redux 應該能從中獲得更多的啟發! 為了更接近 Elm 的靜態類型,[Redux 可以使用一個類似 Flow 的漸進類型解決方案](https://github.com/reduxjs/redux/issues/290) 。
### Immutable
[Immutable](https://facebook.github.io/immutable-js) 是一個可實現持久數據結構的 JavaScript 庫。它性能很好,并且命名符合 JavaScript API 的語言習慣 。
Immutable 及類似的庫都可以與 Redux 對接良好。盡可隨意捆綁使用!
**Redux 并不在意你如何存儲 state,state 可以是普通對象,不可變對象,或者其它類型。** 為了從 server 端寫同構應用或融合它們的 state ,你可能要用到序列化或反序列化的機制。但除此以外,你可以使用任何數據存儲的庫,**只要它支持數據的不可變動性**。舉例說明,對于 Redux state ,Backbone 并無意義,因為 Backbone model 是可變的。
注意,即便你使用支持 cursor 的不可變庫,也不應在 Redux 的應用中使用。整個 state tree 應被視為只讀,并需通過 Redux 來更新 state 和訂閱更新。因此,通過 cursor 來改寫,對 Redux 來說沒有意義。**而如果只是想用 cursor 把 state tree 從 UI tree 解耦并逐步細化 cursor,應使用 selector 來替代。** Selector 是可組合的 getter 函數組。具體可參考 [reselect](http://github.com/faassen/reselect),這是一個優秀、簡潔的可組合 selector 的實現。
### Baobab
[Baobab](https://github.com/Yomguithereal/baobab) 是另一個流行的庫,實現了數據不可變特性的 API,用以更新純 JavaScript 對象。你當然可以在 Redux 中使用它,但兩者一起使用并沒有什么優勢。
Baobab 所提供的大部分功能都與使用 cursors 更新數據相關,而 Redux 更新數據的唯一方法是分發一個 action 。可見,兩者用不同方法,解決的卻是同樣的問題,相互并無增益。
不同于 Immutable ,Baobab 在引擎下還不能實現任何特別有效的數據結構,同時使用 Baobab 和 Redux 并無裨益。這種情形下,使用普通對象會更簡便。
無論如何,Flux 的創造者們[認可](https://twitter.com/jingc/status/616608251463909376)了[Redux](https://twitter.com/fisherwebdev/status/616286955693682688)。
### RxJS
[RxJS](https://github.com/ReactiveX/RxJS) 是管理復雜異步應用非常優秀的方案。[以外,還有致力于構建將人機交互作模擬為相互依賴的可觀測變量的庫](http://cycle.js.org)。
同時使用它和 Redux 有意義么?當然!它們配合得很好。將 Redux store 視作可觀察變量非常簡便,例如:
```js
function toObservable(store) {
return {
subscribe({ next }) {
const unsubscribe = store.subscribe(() => next(store.getState()))
next(store.getState())
return { unsubscribe }
}
}
}
```
使用類似方法,你可以組合不同的異步流,將其轉化為 action ,再提交到 `store.dispatch()` 。
問題在于: 在已經使用了 Rx 的情況下,你真的需要 Redux 嗎? 不一定。[通過 Rx 重新實現 Redux](https://github.com/jas-chen/rx-redux) 并不難。有人說僅需使用一兩句的 `.scan()` 方法即可。這種做法說不定不錯!
如果你仍有疑慮,可以去查看 Redux 的源代碼 (并不多) 以及生態系統 (例如[開發者工具](https://github.com/reduxjs/redux-devtools))。如果你無意于此,仍堅持使用交互數據流,可以去探索一下 [Cycle](http://cycle.js.org) 這樣的庫,或把它合并到 Redux 中。記得告訴我們它運作得如何!
- 自述
- 介紹
- 動機
- 核心概念
- 三大原則
- 先前技術
- 學習資源
- 生態系統
- 示例
- 基礎
- Action
- Reducer
- Store
- 數據流
- 搭配 React
- 示例:Todo List
- 高級
- 異步 Action
- 異步數據流
- Middleware
- 搭配 React Router
- 示例:Reddit API
- 下一步
- 技巧
- 配置 Store
- 遷移到 Redux
- 使用對象展開運算符
- 減少樣板代碼
- 服務端渲染
- 編寫測試
- 計算衍生數據
- 實現撤銷重做
- 子應用隔離
- 組織 Reducer
- Reducer 基礎概念
- Reducer 基礎結構
- Reducer 邏輯拆分
- Reducer 重構示例
- combineReducers 用法
- combineReducers 進階
- State 范式化
- 管理范式化數據
- Reducer 邏輯復用
- 不可變更新模式
- 初始化 State
- 結合 Immutable.JS 使用 Redux
- 常見問題
- 綜合
- Reducer
- 組織 State
- 創建 Store
- Action
- 不可變數據
- 代碼結構
- 性能
- 設計哲學
- React Redux
- 其它
- 排錯
- 詞匯表
- API 文檔
- createStore
- Store
- combineReducers
- applyMiddleware
- bindActionCreators
- compose
- react-redux 文檔
- API
- 排錯