React JS中如何修改子对象属性?控制台打印异常求助
问题分析与解决方案
为什么会出现console.log不一致的情况
浏览器控制台打印引用类型(对象/数组)时,存储的是对象的引用而非打印瞬间的快照。当你展开父对象(newDisplayedAssignment[key])时,控制台会实时读取当前对象状态,若修改操作和控制台展开存在时间差,就可能显示旧值;而直接打印子对象(newDisplayedAssignment[key][assignment])时,控制台会立即截取该子对象的快照,因此能显示正确的新值。
但更核心的问题是你违反了React的不可变数据原则:直接修改传入的对象(哪怕变量名带new)不会触发组件重新渲染,还可能导致状态混乱,这也是你之前深度复制没效果的大概率原因——复制方式不对,没做到真正的深层独立副本。
正确的不可变更新方式
必须创建对象的深层副本,修改副本后返回,确保每一层都是新引用,以下是几种可行实现:
方法1:使用展开运算符逐层复制
function onDateChange(event, newDisplayedAssignment, key, assignment) { // 逐层创建新对象,保证每一层引用都独立 const updatedAssignments = { ...newDisplayedAssignment, [key]: { ...newDisplayedAssignment[key], [assignment]: { ...newDisplayedAssignment[key][assignment], date: event.target.value } } }; console.log(updatedAssignments[key][assignment]); console.log(updatedAssignments[key]); return updatedAssignments; }
方法2:使用structuredClone做深度复制(现代浏览器支持)
function onDateChange(event, newDisplayedAssignment, key, assignment) { // 深度复制整个对象,生成完全独立的副本 const updatedAssignments = structuredClone(newDisplayedAssignment); updatedAssignments[key][assignment]['date'] = event.target.value; console.log(updatedAssignments[key][assignment]); console.log(updatedAssignments[key]); return updatedAssignments; }
方法3:自定义递归深度复制(兼容旧环境)
如果运行环境不支持structuredClone,可以自己实现深度复制函数:
function deepClone(obj) { if (obj === null || typeof obj !== 'object') return obj; if (obj instanceof Date) return new Date(obj.getTime()); if (obj instanceof Array) return obj.map(item => deepClone(item)); const clonedObj = {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { clonedObj[key] = deepClone(obj[key]); } } return clonedObj; } function onDateChange(event, newDisplayedAssignment, key, assignment) { const updatedAssignments = deepClone(newDisplayedAssignment); updatedAssignments[key][assignment]['date'] = event.target.value; console.log(updatedAssignments[key][assignment]); console.log(updatedAssignments[key]); return updatedAssignments; }
额外注意事项
- 调用这个函数后,必须将返回的新对象设置为React状态(比如通过
setState或useState的更新函数),否则组件不会重新渲染,界面也不会同步变化。 - 之前深度复制没效果,大概率是用了浅复制方式(比如
Object.assign仅复制第一层、展开运算符只处理外层),必须确保修改的是完全独立的深层副本。
内容的提问来源于stack exchange,提问作者collinm10
相关产品推荐
相关产品推荐

