React Redux combineReducers 函数在导出时调用我的减速器 2 次,并在 createStore 函数中额外调用一次

React Redux combineReducers function calls my reducers 2 times when its exported and an additional time in the createStore function

我是 Redux 的新手,我想了解为什么 combineReducers 函数会调用 reducer 两次。

我的 reducer/index.js 看起来像这样

  import {combineReducers} from "redux"

const AReducer = (state = "A", action) =>{
    console.log("In A reducer")

    switch (action.type){
        case "Alpha":
            return state + action.payload
        default:
            return state
    }
}

const BReducer = (state = "B", action) =>{
    console.log("In B reducer")
    switch(action.type)
        {
            case "Beta":
                return state + action.payload
            default:
                return state
        }
}

const allReducers = combineReducers({
    A : AReducer,
    B : BReducer
})

export default allReducers

我的 store/index.js 看起来像这样

import {createStore} from "redux";
import allReducers from "../Reducer"


const store = createStore(allReducers, 
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
  )

export default store

并且控制台日志显示了这个

index.js:4 In A reducer
index.js:4 In A reducer
index.js:15 In B reducer
index.js:15 In B reducer
index.js:4 In A reducer
index.js:15 In B reducer

我只想了解为什么会这样。我想更好地了解后台发生的事情

首先,让我们打印 action.

import { combineReducers, createStore } from 'redux';

const AReducer = (state = 'A', action) => {
  console.log('In A reducer, action: ', action);

  switch (action.type) {
    case 'Alpha':
      return state + action.payload;
    default:
      return state;
  }
};

const BReducer = (state = 'B', action) => {
  console.log('In B reducer, action: ', action);
  switch (action.type) {
    case 'Beta':
      return state + action.payload;
    default:
      return state;
  }
};

const allReducers = combineReducers({
  A: AReducer,
  B: BReducer,
});

const store = createStore(allReducers);

日志:

In A reducer, action:  { type: '@@redux/INIT3.j.l.q.g.r' }
In A reducer, action:  { type: '@@redux/PROBE_UNKNOWN_ACTIONn.x.t.b.s.j' }
In B reducer, action:  { type: '@@redux/INIT3.j.l.q.g.r' }
In B reducer, action:  { type: '@@redux/PROBE_UNKNOWN_ACTIONu.8.f.5.c.h' }
In A reducer, action:  { type: '@@redux/INIT3.j.l.q.g.r' }
In B reducer, action:  { type: '@@redux/INIT3.j.l.q.g.r' }

说明

我用AReducer的日志来说明,Breducer也是一样。

combineReducers 函数在内部调用 assertReducerShape() 函数。

assertReducerShape() 函数将使用 init action 调用在 combineReducers 函数中传递的每个缩减器,以检查缩减器是否具有有效的 returned 值。 In A reducer, action: { type: '@@redux/INIT3.j.l.q.g.r' }日志就是这样来的

并且,它还会调用每个带有 unknown actions 的减速器来检查减速器 return 是否为任何未知操作的当前状态,除非它是 undefinedIn A reducer, action: { type: '@@redux/PROBE_UNKNOWN_ACTIONn.x.t.b.s.j' }日志就是这样来的

调用createStore函数时,会dispatch init action. So that every reducer returns their initial state. This effectively populates the initial state tree. This is how In A reducer, action: { type: '@@redux/INIT3.j.l.q.g.r' } log come. This process is mentioned in the documentation, See tips.

另请查看 utils/actionTypes 文件中的 INITPROBE_UNKNOWN_ACTION 操作类型。

const randomString = () =>
  Math.random().toString(36).substring(7).split('').join('.')

const ActionTypes = {
  INIT: `@@redux/INIT${/* #__PURE__ */ randomString()}`,
  REPLACE: `@@redux/REPLACE${/* #__PURE__ */ randomString()}`,
  PROBE_UNKNOWN_ACTION: () => `@@redux/PROBE_UNKNOWN_ACTION${randomString()}`
}

这些action类型是private的,redux内部使用,你不需要处理。你会在 redux dev tools 中看到 dispatched INIT action,不要惊讶。