Redux 架構詳解

Redux 是一種前端「架構模式」,是 Flux 架構的一種變種,用來提供可預測的狀態管理。雖然常常和 React 一塊兒被說起,可是 Redux 卻不只僅只能用於 React,還能夠將其運用到其餘前端庫中,Vue Angular甚至是 jQueryRedux 只是一種架構模式而已,並無和其餘庫綁定在一塊兒。而 React-redux 就是把 ReduxReact.js 結合起來的一個庫。就像 Vuex 同樣,是一個與 Vue.js 結合的 Flux 變種。前端

爲何要用 Redux

也許有人會問:爲何咱們會須要 redux 呢? 嗯... 確實,咱們必需要先了解咱們爲何須要 redux? redux 的出現是爲了解決什麼問題?react

那麼,咱們來考慮這麼一種場景,在你構建的一棵組件樹中,有A、B那麼兩個組件,它們須要共享同一個狀態,你會怎麼辦呢?redux

咱們能夠經過狀態提高的思路,將該狀態提高到附近的公共父組件上面,而後經過 props 把狀態傳遞給子組件,這樣就能夠在AB組件之間共享數據了。確實能夠,可是若是AB的父組件在組件樹向上好幾個組件的位置呢?就須要將狀態經過 props 一級一級往下傳遞,那麼狀態的傳遞路徑就會很是長,並且中間組件根本就不須要訪問這個狀態。並且,若是後續有一個C 組件也要訪問該狀態而且ABC的公共父組件還要往上呢?你就不得不修改以前代碼了。很顯然,這不是一種很好的解決方案,它會讓咱們的代碼維護起來很是痛苦。微信

難道就沒有其餘方法能夠解決這個問題嗎?其實也有的,那就是 reactcontext,一個組件只要往本身的 context 裏面放了某些狀態,那麼這個組件的全部子組件均可以直接訪問這個狀態而不須要經過中間組件的傳遞,看起來問題解決了嘛。架構

咱們雖然解決了狀態傳遞的問題卻引入了新的問題,咱們引入的 context 打破了組件和組件之間經過 props 傳遞數據的規範,極大地加強了組件之間的耦合性。並且 context 就像全局變量同樣,裏面的數據能夠被子組件隨意更改,可能會致使程序不可預測的運行。函數

這時候咱們就該考慮使用 Redux 了,Redux 能夠幫你建立應用的共享狀態,而且不能隨意的更改這些狀態。spa

Redux 的基本概念

咱們已經瞭解了爲何要使用 Redux,那麼咱們先了解下 Redux 的三個基本概念。
設計

Store

咱們能夠經過 createStore 來建立 storecode

import { createStore } from 'redux';
const store = createStore(reducers);

Redux 中,應用程序只能擁有一個 store,用來保存整個應用程序的 state,至關於一個應用程序的共享狀態。對象

咱們能夠經過 store.getState() 來獲取應用程序的當前狀態。可是咱們卻不能隨意的修改狀態,咱們只能經過 store.dispatch(action) 來修改狀態。

修改完狀態以後,咱們但願能夠作些 view 層的改變,這時能夠經過 store.subscribe(() => {}) 來註冊視圖變化的回調函數。

Actions

Actions 是一個 JavaScript 普通對象,用來描述應用程序中發生的一些事情,也是把數據從應用傳遞給 store 的惟一途徑。

咱們約定,action 內必須使用一個字符串類型的 type 字段來表示將要執行的動做,type 通常會被定義成字符串常量。

const ADD_TODO = 'ADD_TODO'

{
  type: ADD_TODO,
  data: 'some data'
}

咱們除了直接以 JavaScript 普通對象的形式來定義 action 以外,也能夠經過函數形式來定義 action,這個函數被稱做 Action 建立函數( actionCreator )。

const ADD_TODO = 'ADD_TODO';

function addTodo(data) {
  return {
    type: ADD_TODO,
    data
  }
}

這裏 action 建立函數 addTodo 很簡單,只是返回一個 action。 咱們能夠經過 store.dispatch 來通知須要修改狀態

store.dispatch(addTodo('some data'));

Reducers

咱們已經知道能夠經過 action 來修改狀態,可是 action 傳遞過來的只是簡單的對象,並無具體處理狀態的邏輯,這就是 reducers 要作的事情了。

Reducer 必須是一個純函數(一個函數的返回結果只依賴於它的參數,而且在執行過程裏面沒有反作用,這個函數就叫作純函數)。由於純函數很是「靠譜」,執行一個純函數不會產生不可預料的行爲,也不會對外部產生影響。

function todoApp(state = { title: 'todoApp', todos: [] }, action) {
  switch (action.type) {
    case ADD_TODO:
      return Object.assign({}, state, {
        todos: [
          ...state.todos,
          {
            data: action.data,
            completed: false
          }
        ]
      })
    default:
      return state
  }
}

todoApp 接收舊的 stateaction,並返回新的 state。注意這裏咱們是將 state 拷貝一份,再添加咱們改動的值去覆蓋原來的數據,從新組合成新的 state 返回,而不是直接修改 state

這是由於若是你直接去改變 state 裏對象的屬性,那麼就須要去比較新舊兩個 state 的區別,而比較兩個 Javascript 對象全部的屬性是否相同就須要對它們進行深比較。可是在真實的應用中 js 的對象都很大,進行深比較的代價十分昂貴。而若是你返回的是一個全新的對象,就只須要比較新舊兩個對象的存儲地址是否相同就能夠了。Redux 就是這麼作的,若是你在 reducer 內部直接修改舊的 state 對象的屬性值,那麼新的 state 和舊的 state 將都指向同一個存儲地址,Redux 會認爲沒有任何改變。

咱們能夠有多個 reducer,每一個 reducer 只負責管理全局 state 中它負責的那部分,每一個 reducerstate 參數能夠都不一樣,分別對應它管理的那部分 state 數據。而後經過 combineReducers 組成根 reducer 用來建立一個 store

import { combineReducers } from 'redux';

const todosReducer = (state = [], action) => {
  // do something
}

const titleReducer = (state = '', action) => {
  // do something
}

const reducer = combineReducers({
  todos: todosReducer,
  title: titleReducer
});

// 等價於
function reducer(state = {}, action) {
  return {
    todos: todosReducer(state.todos, action),
    title: titleReducer(state.title, action)
  }
}

combineReducers 這個函數會調用你的定義的 reducer,每一個 reducer 根據它們的 key(todos, title) 來篩選出 state 中的一部分數據處理並返回一份副本,根 reducer 會把這些副本組合起來造成一個新的大對象。最後根 reducer 將這個大對象傳回給 storestore 再將它設爲最終的狀態。

Redux 工做流程

redux 一些基本概念咱們都清楚了,咱們來總結一下,Redux 爲咱們所作的事情:

  1. 一個存放應用程序共享 state 的地方
  2. 一個去分發 actions 經過純函數修改應用程序共享 state 的機制
  3. 一個能夠訂閱 state 更新的機制

嚴格的單向數據流是 Redux 架構的設計核心。

咱們只要清楚了 redux 中的數據流動的過程就明白 redux 整個工做流程了,咱們從產生一個 action 的切入點來分析數據是怎樣流動的。

  1. 經過用戶在視圖層的交互產生了一個 action,這個 action 多是經過 actionCreator 返回的。
  2. store 接受這這個 action 以後,將當前的 stateaction 一塊兒傳遞給根 reducer
  3. reducerstate 分配給子 reducer 進行處理,子 reducer 返回修改後的副本給根 reducer,根 reducer 整合子 reducer 返回的副本生成一個新的 state 副本返回給 store
  4. store 根據新的 state 觸發視圖層的渲染。
  5. 用戶看到交互後視圖的變化,又高興地發起了一個 action ...

更多精彩內容,歡迎關注微信公衆號~

相關文章
相關標籤/搜索