Dva中model的reducers为什么无法更新state?

皇甫春莉 阅读 75

在Dva项目里写了model的reducers,按照文档应该能更新state,但实际修改后页面完全没反应。

比如这样写:updateName(state, { payload: { name }}) { state.name = name },但是控制台打印state.name还是原来的值。

已经确认action被正确触发了,也检查过connect的绑定没问题,但就是不更新,这是什么情况啊?

我来解答 赞 9 收藏
二维码
手机扫码查看
2 条解答
码农文茹
你这个写法看起来没问题,但问题大概率出在 reducer 里直接修改了 state,Dva(或者说底层的 immer)要求 reducer 必须是纯函数,不能直接改原 state,得返回一个新对象。

你写的 state.name = name 是在原对象上改的,虽然运行时不会报错,但 immer 检测不到变化,所以页面不更新。

正确写法应该是:

return { ...state, name }

或者用新语法(Dva 默认启用了 immer):

state.name = name; return state;

不过后者要确认你的项目确实用了 immer(Dva 2.6+ 默认支持),稳妥起见还是用展开运算符更安全。

另外提醒一下,如果 state 里有嵌套对象(比如 user.info.name),也要注意别直接改嵌套层级,得完整展开或用 immer 的 produce 逻辑,防止注入或不可追踪的变更。

你先试试改 reducer 返回新对象的方式,一般就能解决。
点赞 2
2026-02-26 12:19
宇文诗谣
我之前踩过这个坑,问题出在你对state的修改方式上。Dva的state是不可变的(immutable),你直接写 state.name = name 这种方式其实是直接修改了原来的state对象,这违背了不可变数据的原则,所以不会触发页面更新。

正确的方式是返回一个新的state对象,而不是直接修改原来的state。你可以用对象展开运算符来实现,比如这样:


updateName(state, { payload: { name } }) {
return { ...state, name };
}


这种方式会创建一个新的对象,把原来的state展开,然后覆盖需要修改的字段。页面就能正常响应state的变化了。

我记得刚用Dva的时候也犯过类似的错误,总想着直接改state省事,结果调试了半天才发现问题。另外提醒一下,如果你用的是比较老的JavaScript环境,可能不支持对象展开运算符,可以换成Object.assign来写:


updateName(state, { payload: { name } }) {
return Object.assign({}, state, { name });
}


效果是一样的,看你项目环境选择合适的方式就行。总之记住,永远不要直接修改state,而是返回一个新的对象。
点赞 5
2026-02-18 12:00