優雅地亂玩Redux: Getting Started

szhshp發表於2019-01-16

原創文,最初釋出於 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:

  1. 當前State
  2. 第一步提供給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

複製程式碼

必須滿足以下幾點:

  1. 不能夠修改傳入的值
  2. 不應該提交額外的API/Http請求
  3. 呼叫一些non-pure function, 比如Date.now() 或者 Math.random()(這些函式的結果無法預料)
  4. 可以根據傳入的引數,確定傳回來的值

一個詳細一點的例子:

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, 例如上面返回了ab兩個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, 他需要做這樣的操作

  1. 獲取這個應用的狀態
  2. 可以通過getState()獲取到狀態
  3. 可以通過dispatch(action)來分發動作
  4. 可以通過subscribe(listener)來註冊監聽器
  • 並且還要通過subscribe(listener)的返回值決定是否接觸監聽器

建立Store的例子:

import { createStore } from `redux`
import todoApp from `./reducers`
const store = createStore(todoApp)
複製程式碼

相關文章