Redux分析

1、前言

redux是什麼?

Flux演變而來,做爲狀態容器,提供可預測的狀態管理。html

爲何要用redux?

  • 複雜應用中沒法獲取操做記錄,而狀態的改變每每意味着對應視圖的變化,這一過程是不可控的。前端

    提供一種機制,統一對狀態的查詢、改變、應用進行管理,同時對每一次的狀態變動可進行回溯追蹤vue

  • 多個組件件間可能存在數據的共享以及通訊。react

    這裏能夠簡單將其理解爲充當了eventBus的角色。git

  • 視圖的改變以及數據的獲取等操做雜糅在一塊兒,不利於維護github

    具體操做 -> 狀態變動 -> 觸發視圖更新,這一單向數據流的控制,不只使得對狀態變化的過程變得可控,同時解耦了數據M和視圖V。見下圖,針對相同的action,其數據流轉以及state管理是獨立於前端模板的,所以能夠實現跨框架的複用。 數據和視圖的解耦web

redux適用全部項目?

  • 需不須要使用redux,仍是要結合項目實際以及業務需求,它只是web架構的一種解決方案。好比徹底沒有僅僅由於第二種組件通訊而使用,目前的主流框架如vue有vuex、依賴注入等實現。
  • react使用flux,主要是由於react只提供了組件化UI,視圖模板渲染的一種解決方案,並無提供諸如雙向綁定之類的對數據流的管理。

2、Redux概述

Redux主要有以下幾個概念:vuex

  • action:通常寫法:<type:操做意圖(通常定義爲字符串常量), payload:{text:"要改變的新數據"}>,是store數據的惟一來源。redux

  • store:Redux應用只有一個單一的store。當須要拆分數據處理邏輯時,你應該使用 reducer 組合而不是建立多個store。(經常使用方法:dispatchgetStatesubscribe等)緩存

  • state:數據對象,由store對象管理,經過getStore()只讀

    改變的惟一途徑:由store的dispatch方法對action進行分發,reducer進行處理 範式化。

  • reducer:對action作出相應響應,返回新生成的state(這也是保證可回溯的緣由)。 新生成state有以下幾種方式:

    • Object.assign({}, oldState, newState)
    • {...oldSate, 新值}
    • Immutable
  • 中間件

    這裏強調下Redux的中間件使用,在每次action觸發時,都會先經過層層中間件再真正執行。這個過程賦予了咱們諸如日誌記錄等能力。洋蔥圈模型,和KOA的中間件原理相似。

運做原理圖以下: 運做流程圖

3、Redux分析

如下是仿Redux寫的demo,實現了Redux的基本能力,緩存了操做記錄,進一步擴展能夠實現諸如回退等功能。

如下列出了幾個核心函數:

  • store

    /**
    * store提供的方法:
     *  1. getState:獲取當前state
    *  2. dispatch:觸發行爲
    *  3. subscribe:訂閱事件
     */
     function createStore(reducers, initState) {
        //historyState可用做時光機
        let state = initState, historyState = [{action:'init', state: initState}], listeners = [];
    
        let getState = () => state;
    
        let subscribe = (event) => {
           listeners.push(event);
            /**
             * 註冊事件的同時,獲取事件句柄
             * let fnHandle = fnsubscribe(fn)
             * 刪除對應註冊事件
             * fnHandle();
            *  */
            return () => {
                listeners = listeners.filter(eventItem => eventItem != event);
            }
        }
    
     let dispatch = (action) => {
        //reducer根據action對state作改變,返回全新的state
         state = reducers(state, action);
         historyState.push({action, state})
         //state改變的狀況下,觸發事件
         listeners.forEach(listener => listener());
      }
     return {
          dispatch,
          getState,
           subscribe,
           getHistoryState: () => historyState
       }
    }
    複製代碼
  • 綁定中間件applyMiddleware

    //將中間件綁定到
    let applyMiddleware = middlewares => (createStore) => (...args) => {
      let store = createStore(...args);
       let dispatch = store.dispatch;
      let params = {
          dispatch,
          getState: store.getState
      };
       middlewares = middlewares.map(mw => mw(params));
      //組合中間件,加強dispatch
      //裝飾者模式 & 洋蔥圈,compose對中間件的組合
       dispatch = compose(middlewares)(dispatch);
      //返回加強後的dispatch
       return Object.assign(store, {dispatch});
    }
    複製代碼
  • 使用

    • reducers
      /**
       * 對action作處理,返回全新的state
       */
      function reducers(state, action){
          switch(action){
              case 'add':
                  return state += 1;
              case 'minus':
                  return state -=1;
              default:
                  return 0;
          }
      }
      複製代碼
    • middleware
      /**
      * 中間件(注意中間件的約定格式)
       */
      function middleware1({dispatch, getState}) {
         return function(next) {
             return function(action) {
                 console.log(`【日誌】當前state值:${getState()},執行${action}`);
                next(action);
                console.log(`【日誌】操做完成後,state值:${getState()}`);
           }
        }
      }
      function middleware2({dispatch, getState}) {
         return function(next) {
             return function(action) {
                 console.log(`>>>>>>>>>>>>>>>>>>`);
                  next(action);
               console.log(`<<<<<<<<<<<<<<<<<<`);
            }
       }
      }
      複製代碼
    • 初始化store
      /**
       * 對外暴露:
       *  1. createStore: 產生store
       *  2. applyMiddleware:中間件處理
       */
      let initState = 1;
      let store = applyMiddleware([middleware2, middleware1])(createStore)(reducers, initState);
      
      複製代碼

4、展現

demo展現效果以下:

這裏只是簡單說明redux的能力,具體功能可自行擴展。

完整代碼見:github.com/269117220/w…

參考文獻

相關文章
相關標籤/搜索