React+Redux项目中如何用Immer.js更新嵌套对象的指定属性
错误原因
你之前的代码错误核心是:传入produce处理的是currentJob.job_texts数组,produce返回的是修改后的数组,你直接将数组作为参数传给了接收整个currentJob对象的updateCurrentJob方法,导致原currentJob对象被数组覆盖,所以无法正常运行。
正确实现
首先确保你已经正确安装并导入Immer:
import { produce } from 'immer';
在组件的事件回调中按如下方式编写即可:
function onTextChanged(event) { const newText = event.target.value; // 将完整的currentJob对象作为produce的第一个入参 const updatedJob = produce(props.currentJob, draft => { // 查找匹配id的目标项,直接修改draft对应属性即可 const targetJobText = draft.job_texts.find(item => item.id === props.jobText.id); if (targetJobText) { targetJobText.text = newText; } }); props.updateCurrentJob(updatedJob); }
优化建议
更推荐把状态修改逻辑放到Redux的reducer中处理,组件只需要传递更新所需的参数即可,代码更易维护:
- 组件内触发更新:
function onTextChanged(event) { props.updateJobText(props.jobText.id, event.target.value); } // mapDispatchToProps中新增对应方法 function mapDispatchToProps(dispatch) { return { updateJobText: (id, text) => dispatch({ type: 'UPDATE_JOB_TEXT', payload: { id, text } }) }; }
- Reducer中使用Immer处理不可变更新:
import { produce } from 'immer'; const initialState = { currentJob: { // 其他原有属性 job_texts: [] } }; export default function jobReducer(state = initialState, action) { switch (action.type) { case 'UPDATE_JOB_TEXT': return produce(state, draft => { const { id, text } = action.payload; const target = draft.currentJob.job_texts.find(item => item.id === id); if (target) target.text = text; }); default: return state; } }
Immer会自动生成符合不可变要求的新状态,只会对修改到的节点做更新,不需要全量深拷贝,性能优于_.cloneDeep方案,也完全符合Redux的状态更新规范。
内容的提问来源于stack exchange,提问作者dns_nx
相关产品推荐
相关产品推荐

