深刻淺出理解Redux

Redux是什麼

Redux 是 JavaScript 狀態容器,提供可預測化的狀態管理。前端

它認爲:Web應用是一個狀態機,視圖與狀態一一對應。從架構層面來講,一般但願UI跟數據、邏輯分離,直觀體現就是:UI = render(state)服務器

爲何要用Redux

如今的Web應用涉及大量數據交互、異步操做等,無疑都在增長前端的複雜性,須要維護的state也愈來愈多。而Redux就是試圖讓每一個state變化都是可預測,將應用中全部的action與state統一管理。markdown

Redux的三原則

  • 單一數據源 整個應用state應該只存儲在惟一一個的Store中。
  • 保持狀態只是只讀 不能直接修改state,惟一能改變Store的state方法就是經過觸發一個action對象完成。
  • 數據改變經過純函數完成 action改變state須要經過reducers。

Redux工做流程

在講Redux的工做流程以前,需瞭解幾個Redux相關的核心概念:架構

  • Action:Action能夠當作是應用發出的通知,表示State應該要發生變化了,Action的觸發多是用戶對View層的操做也多是服務器的響應。
  • Action Creator:若是有不少種Action,而每種Action都手寫的話顯得麻煩,因此用定義的Action Creator函數來生成Action。
  • Dispatch:Action發出的惟一方法。
  • Store:整個應用惟一保存數據的地方。
  • State:對Store中保存數據生成某個時點數據快照,該數據集合叫作State。
  • Reducer:Action只是描述了State應要發生變化,而Reducer作的是如何改變State。

具體工做流程: 用戶經過View(或服務器響應)觸發Action,Dispatch方法將Action Creator函數生成的Action派發到Store,Store自動調用Reducer,並向它傳入當前State和Action,Reducer返回新的State,State一旦有變化,Store就會經過監聽函數來更新View。 借用一張圖來描述這一過程: app

image

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

幾個Redux核心概念實例

以從服務器響應文章內容爲例 Action函數

const LOAD_ARTICLES_DETAIL = 'LOAD_ARTICLES_DETAIL'
const LOAD_ARTICLES_DETAIL_SUCCESS = 'LOAD_ARTICLES_DETAIL_SUCCESS'
const LOAD_ARTICLES_DETAIL_ERROR = 'LOAD_ARTICLES_DETAIL_ERROR'
複製代碼

Action Creatorspa

export const loadArticlesDetail = () => ({
  type: LOAD_ARTICLES_DETAIL
})
export const loadArticlesDetailSuccess = result => ({
  type: LOAD_ARTICLES_DETAIL_SUCCESS,
  result
})
export const loadArticlesDetailFailure = error => ({
  type: LOAD_ARTICLES_DETAIL_ERROR,
  error
})
複製代碼

Store設計

const store = createStore(reducers)
複製代碼

Reducer (previousState, action) => (newState)code

export default (state = initalState, action) => {
switch (action.type) {
case LOAD_ARTICLES_DETAIL: {
  return {
    ...state,
    loading: true,
    error: false
  }
}
case LOAD_ARTICLES_DETAIL_SUCCESS: {
  return {
    ...state,
    loading: false,
    error: false,
    articlesDetail: action.result
  }
}
case LOAD_ARTICLES_DETAIL_ERROR: {
  return {
    ...state,
    loading: false,
    error: true
  }
}
default:
  return state
}
}

複製代碼

深刻到Redux的源碼

Redux主要源碼總體結構:

image

  • 入口文件 index.js
export {
  createStore,
  combineReducers,
  bindActionCreators,
  applyMiddleware,
  compose
}
複製代碼

這是入口文件導出的方法,也是Redux支持的方法,這些方法的實如今主工做流程文件和輔助函數文件,接下來看主工做流程。

  • 主工做流程文件 createStore.js createStore方法主要是生成Store,看看它作了哪些事兒:
    • getState方法返回了當前State
    • subscribe方法傳入函數到監聽隊列和返回取消訂閱函數
    • dispatch方法調用Reducer,按順序執行listener,返回Action 輔助源碼文件:
  • applyMiddleware.js:用於加強Store
export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    const store = createStore(reducer, preloadedState, enhancer)
    let dispatch = store.dispatch
    let chain = []

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}
複製代碼

從源碼上看,最後是返回了一個Store和一個被更新過的dispatch方法,實現了對Store的加強。

  • bindActionCreators.js:
export default function bindActionCreators(actionCreators, dispatch) {
  if (typeof actionCreators === 'function') {
    return bindActionCreator(actionCreators, dispatch)
  }
}
複製代碼

使用dispatch把action creator都包裝起來,這樣能夠直接調用它們。

  • combineReducers.js:當應用比較大的時而拆分Reducer,可是傳入Store的Reducer必須是一個函數,因此這個方法的主要功能是用來合併多個Reducer。
  • compose.js
    export default function compose(...funcs) {
      if (funcs.length === 0) {
        return arg => arg
      }
    
      if (funcs.length === 1) {
        return funcs[0]
      }
    
      return funcs.reduce((a, b) => (...args) => a(b(...args)))
    }
    複製代碼
    compose這個方法,傳入的一系列函數,執行的最終結果是把各個函數串聯起來。

總結:

  • Redux 是 JavaScript 狀態容器,提供可預測化的狀態管理。
  • 嚴格的單向數據流是 Redux 架構的設計核心。
  • UI = render(state)
相關文章
相關標籤/搜索