Redux 的基礎概念-API

 

三個基本原則

  • 整個應用只有惟一一個可信數據源,也就是隻有一個 Store
  • State 只能經過觸發 Action 來更改
  • State 的更改必須寫成純函數,也就是每次更改老是返回一個新的 State,在 Redux 裏這種函數稱爲 Reducer

Actions

Action 很簡單,就是一個單純的包含 { type, payload } 的對象,type 是一個常量用來標示動做類型,payload 是這個動做攜帶的數據。Action 須要經過 store.dispatch() 方法來發送。javascript

好比一個最簡單的 action:java

{
  type: 'ADD_TODO', text: 'Build my first Redux app' } 

通常來講,會使用函數(Action Creators)來生成 action,這樣會有更大的靈活性,Action Creators 是一個pure function,它最後會返回一個 action 對象:git

function addTodo(text) { return { type: 'ADD_TODO', text } } 

因此如今要觸發一個動做只要調用 dispatchdispatch(addTodo(text))github

稍後會講到如何拿到 store.dispatchredux

Reducers

Reducer 用來處理 Action 觸發的對狀態樹的更改。app

因此一個 reducer 函數會接受 oldState 和 action 兩個參數,返回一個新的 state:(oldState, action) => newState。一個簡單的 reducer 可能相似這樣:dom

const initialState = { a: 'a', b: 'b' }; function someApp(state = initialState, action) { switch (action.type) { case 'CHANGE_A': return { ...state, a: 'Modified a' }; case 'CHANGE_B': return { ...state, b: action.payload }; default: return state } } 

值得注意的有兩點:ecmascript

  • 咱們用到了 object spread 語法 確保不會更改到 oldState 而是返回一個 newState
  • 對於不須要處理的 action,直接返回 oldState

Reducer 也是 pure function,這點很是重要,因此絕對不要在 reducer 裏面作一些引入 side-effects 的事情,好比:ide

  • 直接修改 state 參數對象
  • 請求 API
  • 調用不純的函數,好比 Data.now() Math.random()

由於 Redux 裏面只有一個 Store,對應一個 State 狀態,因此整個 State 對象就是由一個 reducer 函數管理,可是若是全部的狀態更改邏輯都放在這一個 reducer 裏面,顯然會變得愈來愈巨大,愈來愈難以維護。得益於純函數的實現,咱們只須要稍微變通一下,讓狀態樹上的每一個字段都有一個 reducer 函數來管理就能夠拆分紅很小的 reducer 了:函數

function someApp(state = {}, action) { return { a: reducerA(state.a, action), b: reducerB(state.b, action) }; } 

對於 reducerA 和 reducerB 來講,他們依然是形如:(oldState, action) => newState 的函數,只是這時候的 state 不是整個狀態樹,而是樹上的特定字段,每一個 reducer 只須要判斷 action,管理本身關心的狀態字段數據就行了。

Redux 提供了一個工具函數 combineReducers 來簡化這種 reducer 合併:

import { combineReducers } from 'redux'; const someApp = combineReducers({ a: reducerA, b: reducerB }); 

若是 reducer 函數名字和字段名字相同,利用 ES6 的 Destructuring 能夠進一步簡化成:combineReducers({ a, b })

象 someApp 這種管理整個 State 的 reducer,能夠稱爲 root reducer。

Store

如今有了 Action 和 Reducer,Store 的做用就是鏈接這二者,Store 的做用有這麼幾個:

  • Hold 住整個應用的 State 狀態樹
  • 提供一個 getState() 方法獲取 State
  • 提供一個 dispatch() 方法發送 action 更改 State
  • 提供一個 subscribe() 方法註冊回調函數監聽 State 的更改

建立一個 Store 很容易,將 root reducer 函數傳遞給 createStore 方法便可:

import { createStore } from 'redux'; import someApp from './reducers'; let store = createStore(someApp); // 你也能夠額外指定一個初始 State(initialState),這對於服務端渲染頗有用 // let store = createStore(someApp, window.STATE_FROM_SERVER); 

如今咱們就拿到了 store.dispatch,能夠用來分發 action 了:

let unsubscribe = store.subscribe(() => console.log(store.getState())); // Dispatch store.dispatch({ type: 'CHANGE_A' }); store.dispatch({ type: 'CHANGE_B', payload: 'Modified b' }); // Stop listening to state updates unsubscribe(); 

Data Flow

以上提到的 store.dispatch(action) -> reducer(state, action) -> store.getState() 其實就構成了一個「單向數據流」,咱們再來總結一下。

1. 調用 store.dispatch(action)

Action 是一個包含 { type, payload } 的對象,它描述了「發生了什麼」,好比:

{ type: 'LIKE_ARTICLE', articleID: 42 } { type: 'FETCH_USER_SUCCESS', response: { id: 3, name: 'Mary' } } { type: 'ADD_TODO', text: 'Read the Redux docs.' } 

你能夠在任何地方調用 store.dispatch(action),好比組件內部,Ajax 回調函數裏面等等。

2. Action 會觸發給 Store 指定的 root reducer

root reducer 會返回一個完整的狀態樹,State 對象上的各個字段值能夠由各自的 reducer 函數處理並返回新的值。

  • reducer 函數接受 (state, action) 兩個參數
  • reducer 函數判斷 action.type 而後處理對應的 action.payload 數據來更新並返回一個新的 state

3. Store 會保存 root reducer 返回的狀態樹

新的 State 會替代舊的 State,而後全部 store.subscribe(listener) 註冊的回調函數會被調用,在回調函數裏面能夠經過 store.getState() 拿到新的 State。

+

 

這就是 Redux 的運做流程,接下來看如何在 React 裏面使用 Redux。

相關文章
相關標籤/搜索