ReplaceReducer 导致意外的键错误
Posted
技术标签:
【中文标题】ReplaceReducer 导致意外的键错误【英文标题】:ReplaceReducer causing unexpected key error 【发布时间】:2016-03-09 19:50:08 【问题描述】:我有一个 React 应用程序,它动态加载一个模块,包括模块的 reducer 函数,然后调用 Redux 的 replaceReducer 来替换 reducer。不幸的是,我收到了一个错误
在传递给 createStore 的 initialState 参数中发现了意外的键“bookEntry”。预计会找到已知的 reducer 键之一:“bookList”、“root”。意外的键将被忽略。
bookEntry 是旧reducer上的一个键被替换。从 bookEntry 模块开始并切换到 bookList 会导致此反向错误
在传递给 createStore 的 initialState 参数中发现了意外的键“bookList”。预计会找到已知的 reducer 键之一:“bookEntry”、“root”。意外的键将被忽略。
代码如下 - 取消注释注释代码实际上可以解决此问题,但我猜它不应该是必需的。
我是不是在 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
));
【问题讨论】:
在动态加载代码时,有什么特别的原因要移除之前的reducer吗?我不太明白。一般来说,你希望旧的减速器留下来,而不是被移除。 @DanAbramov - 嗯,没有具体原因。我只是假设传出模块会自行“清理”。这不是我在实践中应该如何做的吗?我应该只触发一个调度以清除其数据,但离开减速器吗? “清理”的目的是什么?通常,您只需保留数据以防用户返回此页面。 @DanAbramov 在尝试像 React 这样的新东西时,我通常会尝试模拟一些 big 的东西,比如我朝九晚五的工作,所以我可以看看它是如何被使用的在“现实生活”中工作(而不是 ToDo)。如果我们保留一切,从日程安排、计费、联系人管理器、任务、文件等,事情很快就会失控。清除我习惯工作的应用程序类型的必要条件与 -- centralreach.com 如果你很好奇(莫名其妙为什么面向公众的网站没有应用程序的屏幕截图 - 它非常清晰) 【参考方案1】:一般我们不建议您在更改路线或加载新模块时“清理”数据。这会使应用程序的可预测性降低。如果我们谈论的是 数十万 条记录,那么当然可以。这是您计划加载的数据量吗?
如果每个页面上只有几千个项目,则卸载它们没有任何好处,并且与您添加到应用程序的复杂性相关的缺点是。因此,请确保您解决的是真正的问题,而不是过早地进行优化。
现在,到警告信息。检查在combineReducers()
中定义。这意味着意外的状态键将被丢弃。在您删除管理 state.bookEntry
的 bookEntry
减速器后,新的根减速器不再识别该部分状态,并且 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));
但是我们推荐的模式是keep the old reducers around。
【讨论】:
谢谢丹 - 根据法律,我必须再等 17 个小时才能获得赏金 :) 非常感谢您提供的信息。我战斗公用事业的日子已经过去了;我很乐意留下旧的减速器,如果确实需要,只需清除过多的数据。您是否有机会看到将其中一些信息写入文档的方法?这几乎是 redux 的 唯一 部分,其中文档有点有限。 @Adam 我现在真的没有时间为文档做贡献。需要一个全面的“动态代码加载”配方,但有人需要拥有它,而我不能。 完全不用担心。你为开发社区做了很多。在我花更多时间用它来更好地理解事情之后,你会接受一些关于 replaceReducer 的更新文档的 PR 吗? @Adam 是的,但我们尽量保持 API 文档简洁。配方会是更正确的形式。以上是关于ReplaceReducer 导致意外的键错误的主要内容,如果未能解决你的问题,请参考以下文章