# 數據流
**嚴格的單向數據流**是 Redux 架構的設計核心。
這意味著應用中所有的數據都遵循相同的生命周期,這樣可以讓應用變得更加可預測且容易理解。同時也鼓勵做數據范式化,這樣可以避免使用多個且獨立的無法相互引用的重復數據。
如果這些理由還不足以令你信服,讀一下 [動機](../introduction/Motivation.md) 和 [Flux 案例](https://medium.com/@dan_abramov/the-case-for-flux-379b7d1982c6),這里面有更加詳細的單向數據流優勢分析。雖然 [Redux 不是嚴格意義上的 Flux](../introduction/PriorArt.md),但它們有共同的設計思想。
Redux 應用中數據的生命周期遵循下面 4 個步驟:
1. **調用** [`store.dispatch(action)`](../api/Store.md#dispatch)。
[Action](Actions.md) 就是一個描述“發生了什么”的普通對象。比如:
```js
{ type: 'LIKE_ARTICLE', articleId: 42 }
{ type: 'FETCH_USER_SUCCESS', response: { id: 3, name: 'Mary' } }
{ type: 'ADD_TODO', text: 'Read the Redux docs.' }
```
可以把 action 理解成新聞的摘要。如 “瑪麗喜歡 42 號文章。” 或者 “todolist 里添加了'學習 Redux 文檔'”。
你可以在任何地方調用 [`store.dispatch(action)`](../api/Store.md#dispatch),包括組件中、XHR 回調中、甚至定時器中。
2. **Redux store 調用傳入的 reducer 函數。**
[Store](Store.md) 會把兩個參數傳入 [reducer](Reducers.md): 當前的 state 樹和 action。例如,在這個 todo 應用中,根 reducer 可能接收這樣的數據:
```js
// 當前應用的 state(todos 列表和選中的過濾器)
let previousState = {
visibleTodoFilter: 'SHOW_ALL',
todos: [
{
text: 'Read the docs.',
complete: false
}
]
}
// 將要執行的 action(添加一個 todo)
let action = {
type: 'ADD_TODO',
text: 'Understand the flow.'
}
// reducer 返回處理后的應用狀態
let nextState = todoApp(previousState, action)
```
注意 reducer 是純函數。它僅僅用于計算下一個 state。它應該是完全可預測的:多次傳入相同的輸入必須產生相同的輸出。它不應做有副作用的操作,如 API 調用或路由跳轉。這些應該在 dispatch action 前發生。
3. **根 reducer 應該把多個子 reducer 輸出合并成一個單一的 state 樹。**
根 reducer 的結構完全由你決定。Redux 原生提供[`combineReducers()`](../api/combineReducers.md)輔助函數,來把根 reducer 拆分成多個函數,用于分別處理 state 樹的一個分支。
下面演示 [`combineReducers()`](../api/combineReducers.md) 如何使用。假如你有兩個 reducer:一個是 todo 列表,另一個是當前選擇的過濾器設置:
```js
function todos(state = [], action) {
// 省略處理邏輯...
return nextState
}
function visibleTodoFilter(state = 'SHOW_ALL', action) {
// 省略處理邏輯...
return nextState
}
let todoApp = combineReducers({
todos,
visibleTodoFilter
})
```
當你觸發 action 后,`combineReducers` 返回的 `todoApp` 會負責調用兩個 reducer:
```js
let nextTodos = todos(state.todos, action)
let nextVisibleTodoFilter = visibleTodoFilter(state.visibleTodoFilter, action)
```
然后會把兩個結果集合并成一個 state 樹:
```js
return {
todos: nextTodos,
visibleTodoFilter: nextVisibleTodoFilter
}
```
雖然 [`combineReducers()`](../api/combineReducers.md) 是一個很方便的輔助工具,你也可以選擇不用;你可以自行實現自己的根 reducer!
4. **Redux store 保存了根 reducer 返回的完整 state 樹。**
這個新的樹就是應用的下一個 state!所有訂閱 [`store.subscribe(listener)`](../api/Store.md#subscribe) 的監聽器都將被調用;監聽器里可以調用 [`store.getState()`](../api/Store.md#getState) 獲得當前 state。
現在,可以應用新的 state 來更新 UI。如果你使用了 [React Redux](https://github.com/gaearon/react-redux) 這類的綁定庫,這時就應該調用 `component.setState(newState)` 來更新。
## 下一步
現在你已經理解了 Redux 如何工作,是時候[結合 React 開發應用](UsageWithReact.md)了。
> ##### 高級用戶使用注意
>
> 如果你已經熟悉了基礎概念且完成了這個教程,可以學習[高級教程](../advanced/README.md)中的[異步數據流](../advanced/AsyncFlow.md),你將學到如何使用 middleware 在 [異步 action](../advanced/AsyncActions.md) 到達 reducer 前處理它們。
- 自述
- 介紹
- 動機
- 核心概念
- 三大原則
- 先前技術
- 學習資源
- 生態系統
- 示例
- 基礎
- 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
- 排錯