原創文,最初釋出於 szhshp的第三邊境研究所 , 轉載請註明
個人筆記, 基於官方英文教程, 新增了一些批註, 有一些單詞翻譯起來真困難
Redux基於嚴格單向資料流實現
反正就是為了打破React自身的資料流而建立的
LifeCycle
1. 呼叫store.dispatch(action)
- 可以在任何地方呼叫這個函式,只要引用store進來就可以了.
- 甚至可以在AJAX callback中, 或者setInterval裡面呼叫
action的格式如下:
{ type: `LIKE_ARTICLE`, articleId: 42 }
{ type: `FETCH_USER_SUCCESS`, response: { id: 3, name: `Mary` } }
{ type: `ADD_TODO`, text: `Read the Redux docs.` }
複製程式碼
通過這個
action
對於使用者操作的描述可以變得非常的具象
2. Reducer接收Action
預設會提交兩個引數給Reducer:
- 當前State
- 第一步提供給
dispatcher
的引數action
3. Root Reducer會將所有sub reducer的結果給結合起來並返回
參考下文提到的
combineReducers()
的使用示例
4. Redux會儲存最後結合起來了的State並且呼叫各個監聽器
現在這個時候已經獲取到了下一個狀態了
如果我使用store.subscribe(listener)
註冊了個監聽器,會在這個時候被呼叫,並且可以通過store.getState()
獲取到當前的狀態
最後通過更新之後的狀態重新整理UI
Key Concepts
- 使用Pure Function來描述State變化
- 即通過各種Dispatcher將狀態變化的請求提交給reducer來處理, reducer僅僅返回下一個狀態
pure function: 可以根據傳入的值預測結果,並且不會影響其他值, 即不改變傳入的值也不會建立閉包
- 因為reducer是一個pure function, 裡面不應該對任何狀態進行修改
- 所有的狀態變化通過一個大的Dispatcher進行分發
- 因此所有的狀態變化都應該提交到這個Dispatcher上面, 這樣就不會出現不同層次的混亂的資料流了
Reducer
基本格式:
(previousState, action) => newState
複製程式碼
必須滿足以下幾點:
- 不能夠修改傳入的值
- 不應該提交額外的API/Http請求
- 呼叫一些non-pure function, 比如
Date.now()
或者Math.random()
(這些函式的結果無法預料) - 可以根據傳入的引數,確定傳回來的值
一個詳細一點的例子:
export default (state = 0, action) => {
switch (action.type) {
case `INCREMENT`:
return state + 1
case `DECREMENT`:
return state - 1
default:
return state
}
}
複製程式碼
- 會根據會根據傳入的
action
的型別進行不同的處理 - 另外
action
不一定要字串,可以傳更多型別,甚至可以傳一個obj進來 - 記住一定要返回新的狀態, 一定要覆蓋到所有的情況
關於多個同級Reducer
可以通過combineReducers
函式返回多個sub-Reducer, 例如上面返回了a
和b
兩個reducer
import { combineReducers } from `redux`
const a = (state = 0, action) => {
switch (action.type) {
case `INCREMENT`:
return state + 1
default:
return state
}
}
const b = (state = 0, action) => {
switch (action.type) {
case `INCREMENT`:
return state + 2
default:
return state
}
}
const e = combineReducers({
a,
b
})
export default e
複製程式碼
如果我們在reducer裡面提供了多個函式
那麼當我們分發一個特定動作的時候, 比如
console.log( store.dispatch({type: `INCREMENT`}) )
複製程式碼
這個動作就會提交到所有的函式之上, 也就是說, 上方a
會接收這個動作,b
也會接受這個動作,然後以下面的格式進行返回:
{
a: 1, //經過a處理之後的狀態
b: 2 //經過b處理之後的狀態
}
複製程式碼
類似於用引數{state, action}便利並執行了整個reducer裡面所有reducer函式
Store
用於分發Action到Reducers, 他需要做這樣的操作
- 獲取這個應用的狀態
- 可以通過
getState()
獲取到狀態 - 可以通過
dispatch(action)
來分發動作 - 可以通過
subscribe(listener)
來註冊監聽器
- 並且還要通過
subscribe(listener)
的返回值決定是否接觸監聽器
建立Store的例子:
import { createStore } from `redux`
import todoApp from `./reducers`
const store = createStore(todoApp)
複製程式碼