Redux分析

6386 ワード

Reduxは何ですか
ReduxはJavascript状態容器であり、予測可能な状態管理を提供する.
Reduxの機能と役割
  • 状態を一つのstateに統一し、storeによってこのstate
  • を管理する.
  • storeはreducerのshopによって
  • を作成します.
  • storeはdispatchのactionを通して、reducerによって統一的に
  • を更新します.
  • 毎回dispatchを使用すると、subscribeによってstoreの変化を監視することができます.
    適用シーン
  • 複数ページの共有が必要なデータ
  • 地方のデータが変わりました.他のところのデータも同期して
  • を変更します.
    シーンは適用されません
  • データは、単一のコンポーネントまたは単一のスコープだけで
  • を使用する.
  • データの変更後、再レンダリングする必要はありません.
    Reduxとグローバルオブジェクトの違いは何ですか?
  • Reduxのデータはstoreに保存されています.dispatchの一つのactionによってしか修正できません.デバッグに便利です.どんな変更も一回の変更記録があります.
  • グローバルオブジェクトの値は直接的に修正できます.修正後は記録がなく、調整が不便です.不適切な使用はグローバル変数汚染を引き起こしやすいです.
    原理解析を実現する
    Reduxのワークフローは:
  • 作成store、すなわち、createStore()
  • は、複数のreducerを一つのreducer、すなわち、commbindReducers()
  • に統合する.
  • 中間部品、すなわちappyMiddlewareを適用する()
  • ソースディレクトリには、compose、bindActioCreatorsの2つのファイルが含まれています.この2つのファイルは主にいくつかの方法を提供するためのものです.
    それぞれのソースコードを解析します.
    createStore
    キーコードは以下の通りです.
    export default function createStore(reducer, preloadedState, enhancer) {
      if (enhancer   ) {
        return enhancer(createStore)(reducer, preloadedState)
      }
    
      let currentReducer = reducer
      let currentState = preloadedState
      let currentListeners = []
      let nextListeners = currentListeners
      let isDispatching = false
    
      //      state
      function getState() {
        return currentState
      }
    
      //         ,   dispatch                 
      function subscribe(listener) {
        let isSubscribed = true
    
        //  currentListeners       
        ensureCanMutateNextListeners()
        //        push      
        nextListeners.push(listener)
    
        return function unsubscribe() {
          isSubscribed = false
          ensureCanMutateNextListeners()
          const index = nextListeners.indexOf(listener)
          nextListeners.splice(index, 1)
        }
      }
    
      function dispatch(action) {
        try {
          isDispatching = true
          //       state,       action,      state
          currentState = currentReducer(currentState, action)
        } finally {
          isDispatching = false
        }
    
        const listeners = (currentListeners = nextListeners)
        for (let i = 0; i < listeners.length; i++) {
          const listener = listeners[i]
          //           
          listener()
        }
    
        return action
      }
    
      return {
        dispatch,
        subscribe,
        getState,
      }
    }
    
    
    上記からわかるように、createStore方法でstoreを作成しました.作成後は直接storeを返しませんでした.操作storeに関するいくつかの方法を返しました.主にgetsStore、subscribe、dispachがあります.
    get State
      function getState() {
        return currentState;
      }
    
    createStoreによって作成されたstoreは、直接にその中のデータにアクセスするにはget Stateによってしか返されないデータは、currentStateオブジェクトの参照であり、直接に修正することができますが、reudxはこのようにしない方がいいと提案しています.
    compse
    composeの役割は、複数の方法を一つの包装にすることです.
    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(funcA, funcB, funcC, funD)出力結果は:funcA(funcB(func(funcD())))commbineReducers
    commbineReducersを知るには、先にreducerが何かを知るべきですか?その役割は何ですか?
    reducerは、reduxがdispatchのactionを通じて、storeの純粋な関数方法を更新するために用いられる.更新storeのreducerは一つしかないかもしれませんが、業務量が大きく、機能モジュールがたくさん区分されています.一つのreducerだけを使ってデータを更新するとreducerが長くなります.後期にbugに遭遇した場合は、検査が困難になりますので、reducerをstore作成時の構造に従って複数のreducerに分割することができます.最後にcommbineReducersを通じて一つのreducerに合併します.
    export default function combineReducers(reducers) {
      //         reducer      key
      const reducerKeys = Object.keys(reducers)
      const finalReducers = {}
      for (let i = 0; i < reducerKeys.length; i++) {
        const key = reducerKeys[i]
    
        //   reducer       ,       reducer
        if (typeof reducers[key] === 'function') {
          finalReducers[key] = reducers[key]
        }
      }
      //         reducer   key
      const finalReducerKeys = Object.keys(finalReducers)
    
      let shapeAssertionError
      try {
        //      reducer       ,     reducer                ,           
        assertReducerShape(finalReducers)
      } catch (e) {
        shapeAssertionError = e
      }
    
      return function combination(state = {}, action) {
        if (shapeAssertionError) {
          throw shapeAssertionError
        }
    
        let hasChanged = false
        const nextState = {}
        for (let i = 0; i < finalReducerKeys.length; i++) {
          //       reducer key
          const key = finalReducerKeys[i]
          //       reducer
          const reducer = finalReducers[key]
          //    key       state  
          const previousStateForKey = state[key]
          //       state  ,   action,   reducer          state
          const nextStateForKey = reducer(previousStateForKey, action)
          //             state  
          nextState[key] = nextStateForKey
          //             ,         
          hasChanged = hasChanged || nextStateForKey !== previousStateForKey
        }
        //        ,      state,       ,       state
        return hasChanged ? nextState : state
      }
    }
    
    appyMiddleware
    中間ボタンは何ですか?まずコアコードを見てください.
    export default function applyMiddleware(...middlewares) {
      //   applyMiddleware  ,        store    
      return createStore => (...args) => {
        const store = createStore(...args)
    
        const middlewareAPI = {
          getState: store.getState,
          dispatch: (...args) => dispatch(...args)
        }
        //           ,              store    dispatch   ,     
        const chain = middlewares.map(middleware => middleware(middlewareAPI))
        //    compose                  
        dispatch = compose(...chain)(store.dispatch)
    
        return {
          ...store,
          dispatch
        }
      }
    }
    
    上記のステップを経て、中間キーは通常action関数に戻ります.dispatchを書き換えます.今度はdispatchを呼び出します.実は書き換えたdispatchを呼び出します.このようにdispatchとreducerの間に、カスタムで実行できる方法を追加しました.dispatchとreducerの間で、データを要求するなどの非同期操作ができます.ログなどの機能を印刷します.これらの機能を全部実行した後に、dispatchの本当の純粋なactionを直して、reducerを修正します.このように既存のコードを修正しない上に、中間挿入操作の機能を達成しました.
    どのようにReactフレームと組み合わせて使うか?
    react-reduxフレームを使って、私達の実現を助けてくれます.
    具体的な実現を理解して、react-reduxソースコードをクリックして解析します.
    Q&A
  • dispatchは同期ですか?それとも非同期ですか?dispatchは同期してstoreを更新します.
  • はなぜreactレンダリングを使用する時に非同期なのですか?reduxがreactの使用を結合する時、実はconnectという高次のコンポーネントを使ってデータの更新を実現していますので、storeのデータが変化したことを傍受した後、reactのsetsState方法を呼び出してページを再レンダリングします.setsStateは非同期です.だからdispachは非同期ではなく、setsStateは非同期です.
  • reduxのsubscribeはどうやって実現されますか?
  • 参照リンク
  • https://www.redux.org.cn/
  • https://juejin.im/post/5b9617835188255c781c9e2f