ReplaceReducer 导致意外的键错误

ReplaceReducer causing unexpected key error

我有一个动态加载模块的 React 应用程序,包括模块的 reducer 函数,然后调用 Redux 的 replaceReducer 来替换 reducer。不幸的是,我收到

的错误

Unexpected key "bookEntry" found in initialState argument passed to createStore. Expected to find one of the known reducer keys instead: "bookList", "root". Unexpected keys will be ignored.

其中 bookEntry 正在更换的旧减速器上的键。从 bookEntry 模块开始并切换到 bookList 会导致此反向错误

Unexpected key "bookList" found in initialState argument passed to createStore. Expected to find one of the known reducer keys instead: "bookEntry", "root". Unexpected keys will be ignored.

代码在下面 - 取消注释注释代码实际上解决了这个问题,但我猜不应该需要它。

我是不是在 Redux 上做错了什么使得这段代码成为必要?

function getNewReducer(reducerObj){
    if (!reducerObj) return Redux.combineReducers({ root: rootReducer });

    //store.replaceReducer(function(){
    //    return {
    //        root: rootReducer()
    //    }
    //});

    store.replaceReducer(Redux.combineReducers({
        [reducerObj.name]: reducerObj.reducer,
        root: rootReducer
    }));
}

一般来说我们建议您在更改路由或加载新模块时“清理”数据。这使得应用程序有点不可预测。如果我们谈论的是 数十万 条记录,那当然可以。这是您计划加载的数据量吗?

如果每个页面上只有几千个项目,卸载它们没有任何好处,而且会增加应用程序的复杂性带来不利影响。因此,请确保您正在解决一个真正的问题,而不是过早地优化。

现在,转到警告消息。检查在 combineReducers() 内定义。这意味着意外的状态密钥将被丢弃。删除管理 state.bookEntrybookEntry reducer 后,新的根 reducer 不再识别那部分状态,并且 combineReducers() 记录了一条警告,它将被丢弃。 请注意,这是一个警告,而不是一个错误。您的代码运行得很好。我们使用console.error()来突出警告,但实际上并没有抛出,所以你可以放心地忽略它。

我们真的不想让警告可配置,因为您实际上是在隐式删除部分应用程序状态。通常人们这样做是错误的,而不是故意的。所以我们想就此发出警告。如果你想绕过警告,最好的办法是手动编写根减速器(目前由 combineReducers() 生成)。它看起来像这样:

// I renamed what you called "root" reducer
// to "main" reducer because the root reducer
// is the combined one.
let mainReducer = (state, action) => ...

// This is like your own combineReducers() with custom behavior
function getRootReducer(dynamicReducer) {
  // Creates a reducer from the main and a dynamic reducer
  return function (state, action) {
    // Calculate main state
    let nextState = {
      main: mainReducer(state.main, action)
    };

    // If specified, calculate dynamic reducer state
    if (dynamicReducer) {
      nextState[dynamicReducer.name] = dynamicReducer.reducer(
        nextState[dynamicReducer.name],
        action
      );
    }

    return nextState;
  };
}

// Create the store without a dynamic reducer
export function createStoreWithoutDynamicReducer() {
  return Redux.createStore(getRootReducer());
}

// Later call this to replace the dynamic reducer on a store instance
export function setDynamicReducer(store, dynamicReducer) {
  store.replaceReducer(getRootReducer(dynamicReducer));
}

但是我们推荐的模式是