使用redux-toolkit createSlice实现state部分重置的写法是否符合规范
常见问题根因
- 第一版代码失效的原因和你的判断完全一致:
createSlice内部的reducer默认基于Immer封装了draft代理对象,Immer只会追踪你对draft对象本身的属性修改操作,如果你在函数内部直接给局部的state变量重新赋值一个新对象(比如state = { ...initialState }),这个操作根本不会被Immer感知,函数执行结束后还是会返回原代理的draft对象,所有重置逻辑全部无效。 - 第一版代码本身还有逻辑错误:
state.username = state.payload、state.dateOfBirth = state.dateOfBirth两行不仅错把action的payload引用写成了state上的属性,逻辑也完全偏离需求——就算赋值操作生效,这两行也是从刚被重置为空的initialState里取null值覆盖,根本达不到保留旧字段的效果。
官方支持的实现方式
RTK对这类部分重置的场景,没有强制要求必须用Immer的draft修改语法,两种写法都是完全符合官方规范的:
- 整对象返回的写法(你目前的可运行写法属于这类)
只要reducer直接返回一个全新的普通对象,Immer会自动跳过draft追踪逻辑,直接把这个返回值替换成整个新state,和传统Redux的纯函数返回新state的逻辑完全兼容,是完全合规的写法。注意:你当前的可运行代码里有个非常容易被忽略的笔误:
你写的username: state.payload是错误的。按照需求,这里应该从旧的draft state里取之前保存的username值(也就是username: state.username)——现在代码里写的state.payload是不存在的属性,实际运行时会得到undefined。另外你迁移前的旧代码里也有同类大小写问题:initialState定义的是小写username,旧reducer里取的是state.userName(大写N),这个值实际永远取不到,迁移的时候可以一起修正。
修正后的写法就是:userSetHomeTown: { reducer: (state, action) => ({ ...initialState, homeTown: action.payload, // 从旧state里取要保留的字段 username: state.username, dateOfBirth: state.dateOfBirth, }), }, - 基于Immer draft的逐字段修改写法
如果更习惯Immer的语法,完全可以不展开整个对象,直接在draft上把需要重置的字段改回初始值即可,要保留的字段完全不用动:userSetHomeTown: (state, action) => { // 直接更新需要设置的新值 state.homeTown = action.payload // 把需要重置的非保留字段逐一改回初始值 state.address = initialState.address state.postCode = initialState.postCode state.floor = initialState.floor // username、dateOfBirth属于要保留的字段,不需要做任何修改 }
写法选择建议
- 如果需要重置的字段占比很高,整对象展开返回的写法代码更简洁,不容易漏写需要重置的字段
- 如果只有少量字段需要重置,逐字段改draft的写法可读性更好,也不需要处理对象展开的顺序问题
内容的提问来源于stack exchange,提问作者tschaka1904
相关产品推荐
相关产品推荐

