You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何React子组件更新state会修改父组件对象引用?求解决方案

问题原因

你遇到的问题核心是引用类型的浅拷贝导致的共享内存地址:

  1. 父组件的obj.values是嵌套对象,属于引用类型,当你用useState(obj.values)初始化子组件状态时,inp和父组件的obj.values指向的是同一个内存地址,并不是独立的副本。
  2. 你在setInp里做的{ ...prev }只是浅拷贝——它只会复制外层对象的键,但里面的per1、per2这些子对象仍然和原obj.values里的子对象共享引用。所以当你修改nD[k1][k2]时,本质上还是在修改原父组件对象的属性值。
解决思路

要彻底切断子组件状态和父组件对象的引用关联,需要做深拷贝,同时在更新状态时也要保证嵌套对象的独立性。

1. 初始化状态时做深拷贝

不要直接把父组件的obj.values传给useState,而是先创建一个完全独立的深拷贝:

const ChildComponent = ({obj}) => {
  // 方式1:用JSON序列化/反序列化(适合无函数、Symbol等特殊类型的对象)
  const [inp, setInp] = useState(JSON.parse(JSON.stringify(obj.values)));

  // 方式2:手动递归深拷贝(适合复杂类型场景)
  // const deepClone = (obj) => {
  //   if (typeof obj !== 'object' || obj === null) return obj;
  //   const clone = Array.isArray(obj) ? [] : {};
  //   for (const key in obj) {
  //     clone[key] = deepClone(obj[key]);
  //   }
  //   return clone;
  // };
  // const [inp, setInp] = useState(deepClone(obj.values));
  
  // ...后续代码
}

2. 更新状态时避免修改原引用

在setInp的回调里,不仅要拷贝外层对象,还要拷贝你要修改的嵌套子对象,确保每一层都是独立的:

const onChange = useCallback(({target}) => {
 setInp((prev) => {
   // 1. 拷贝外层对象
   const newInp = { ...prev };
   // 2. 拷贝要修改的子对象(k1对应的对象,比如per1)
   newInp[k1] = { ...newInp[k1] };
   // 3. 修改拷贝后的子对象属性
   newInp[k1][k2] = target.value; 
   return newInp;
 })
}, [k1, k2]); // 注意依赖数组要加上k1、k2,避免闭包问题

如果嵌套层级更深,手动拷贝会很繁琐,可以用immer库简化——它允许你用“修改”的写法生成不可变对象:

import { produce } from 'immer';

const onChange = useCallback(({target}) => {
 setInp(produce(prev => {
   prev[k1][k2] = target.value;
 }));
}, [k1, k2]);

3. 验证obj.values与inp是否相等

因为是复杂嵌套对象,不能直接用===(它只会比较引用地址),需要做深比较:

  • 自己实现递归比较函数:
const isDeepEqual = (a, b) => {
  if (a === b) return true;
  if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) return false;
  const keysA = Object.keys(a);
  const keysB = Object.keys(b);
  if (keysA.length !== keysB.length) return false;
  for (const key of keysA) {
    if (!keysB.includes(key) || !isDeepEqual(a[key], b[key])) return false;
  }
  return true;
};

// 使用示例
const isEqual = isDeepEqual(obj.values, inp);
  • 或者使用lodash的isEqual方法(如果项目已引入该库):
import isEqual from 'lodash/isEqual';

const isEqual = isEqual(obj.values, inp);

内容的提问来源于stack exchange,提问作者GTemp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 11:45:29