Redux记录:Store是如何自动调用reducers来处理action的

Posted HelloWorld_EE

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redux记录:Store是如何自动调用reducers来处理action的相关的知识,希望对你有一定的参考价值。

Redux记录:Store是如何自动调用reducers来处理action的

作为一个后端程序员,经常也要写一点前端、维护一下前端。因此一直在与前端打交道,但是一直没有理解当用户操作view通过dispatch发出 action之后,我们定义的一系列的reducer是如何来自动执行处理的。

先说结论:当用户操作view之后发出一个action,store会遍历所有的reducers来依次处理这个action来改变state。

今天浏览自己所在公司的官方博客,发现了这篇文章:Redux从设计到源码,仔细拜读了一下,收获很大,也解决了自己一直以来的困惑。

借此机会,自己也梳理一下。

在前端代码,自己经常看到类似如下的代码:

    let store = createStore(reducers, undefined, compose(
        applyMiddleware(
            thunk,
            fetchMiddleware
        ),
        window.devToolsExtension ? window.devToolsExtension() : f => f
    ));

其中,reducers如下:

    let reducers = combineReducers(AReducer, BReducer,CReducer);//AReducer等是我们自己定义的reducer

那么,当一个type=“A”的action产生后,是如何去这些AReducer, BReducer,CReducer来匹配查找然后进行处理的呢?自己当时的猜想是遍历所有的,看了源码之后原来真的是这样。

combineReducers

先看combineReducers的源码里面做了些什么,源码如下:

    export default function combineReducers(reducers) 
      const reducerKeys = Object.keys(reducers)
      const finalReducers = 
      for (let i = 0; i < reducerKeys.length; i++) 
        const key = reducerKeys[i]

        if (process.env.NODE_ENV !== 'production') 
          if (typeof reducers[key] === 'undefined') 
            warning(`No reducer provided for key "$key"`)
          
        

        if (typeof reducers[key] === 'function') 
          finalReducers[key] = reducers[key]
        
      
      const finalReducerKeys = Object.keys(finalReducers)

      let unexpectedKeyCache
      if (process.env.NODE_ENV !== 'production') 
        unexpectedKeyCache = 
      

      let shapeAssertionError
      try 
        assertReducerShape(finalReducers)
       catch (e) 
        shapeAssertionError = e
      

      //返回的是如下这个函数,用于处理action
      return function combination(state = , action) 
        if (shapeAssertionError) 
          throw shapeAssertionError
        

        if (process.env.NODE_ENV !== 'production') 
          const warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache)
          if (warningMessage) 
            warning(warningMessage)
          
        

        let hasChanged = false
        const nextState = 
        for (let i = 0; i < finalReducerKeys.length; i++) 
          const key = finalReducerKeys[i]
          const reducer = finalReducers[key]
          const previousStateForKey = state[key]
          const nextStateForKey = reducer(previousStateForKey, action)
          if (typeof nextStateForKey === 'undefined') 
            const errorMessage = getUndefinedStateErrorMessage(key, action)
            throw new Error(errorMessage)
          
          nextState[key] = nextStateForKey
          hasChanged = hasChanged || nextStateForKey !== previousStateForKey
        
        return hasChanged ? nextState : state
      
    

上面的代码比较长,只需要注意两点即可:

1、将一系列的reducer以(reducerKey,reducer)存储在finalReducers中。

2、返回的函数将在store中自动调用,来处理action。至于如何处理的,下面分析完createStore之后将会分析。

createStore

下面是createStore方法的部分源码,由于store.dispatch(action)是用来分发action,这是修改state的唯一方式,基于此我们这里只关注dispatch方法,因此只对其进行了保留,如果想对其他方法有了解,可以参考博文:Redux从设计到源码,

    export default function createStore(reducer, preloadedState, enhancer) 
        //省略类型检查      
        let currentReducer = reducer
        let currentState = preloadedState
        let currentListeners = []
        let nextListeners = currentListeners
        let isDispatching = false

        //省略其他方法,只保留了dispatch方法   
        function dispatch(action) 
          //省略了类型检查   
          try 
            isDispatching = true
            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
        

      

store.dispatch()方法总结:

1、调用Reducer,传参(currentState,action)。

2、按顺序执行listener。

3、返回action。

下面分析第一点:调用Reducer,传参(currentState,action),即如下这行代码

currentState = currentReducer(currentState, action) 

前面我们说过,currentReducer所指的就是由这行代码let reducers = combineReducers(AReducer, BReducer,CReducer);所产生的reducers,这个reducers是如下这个函数:

    function combination(state = , action) 
        //省略了部分检查代码

        let hasChanged = false
        const nextState = 
        //对所有的reducers进行遍历来处理action。
        for (let i = 0; i < finalReducerKeys.length; i++) 
          const key = finalReducerKeys[i]
          const reducer = finalReducers[key]
          const previousStateForKey = state[key]
          //利用这个reducer来处理action
          const nextStateForKey = reducer(previousStateForKey, action)
          if (typeof nextStateForKey === 'undefined') 
            const errorMessage = getUndefinedStateErrorMessage(key, action)
            throw new Error(errorMessage)
          
          //保存state并判断状态是否改变了。
          nextState[key] = nextStateForKey
          hasChanged = hasChanged || nextStateForKey !== previousStateForKey
        
        return hasChanged ? nextState : state
       

上面比较简单哈,看完这里的源码是不是就理解了,当用户操作view产生一个action之后,store是如何自动调用reducers来处理action的哈。

以上是关于Redux记录:Store是如何自动调用reducers来处理action的的主要内容,如果未能解决你的问题,请参考以下文章

Redux

Redux

redux与react-redux

redux 中的 action、reducer 和 store 有啥区别?

Redux 与 Vuex 的区别总结

我如何在 react redux 中访问另一个 reducer 的状态。 reducer 和 store 之间的状态流