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

React中useRef嵌套对象更新异常:添加属性时原属性被覆盖

React useRef嵌套对象更新时覆盖原有属性问题解决

问题场景

在React中定义了如下嵌套结构的useRef对象:

const obj = useRef({
    category1: [
      { title: { name1: 'value1' } },
      { title: { name2: 'value2' } }
    ],
    category2: [
      { title: { name3: 'value3' } },
      { title: { name4: 'value4' } }
    ]
  });

尝试给category1指定索引的元素添加newTitle对象时,原有title属性被意外覆盖,得到错误结果。

期望结果:

const obj = useRef({
   category1: [
     { title: { name1: 'value1' } },
     { title: { name2: 'value2' }, newTitle: { name5: 'value5' } }
   ],
   category2: [
     { title: { name3: 'value3' } },
     { title: { name4: 'value4' } }
   ]
 });

实际错误结果:

const obj = useRef({
    category1: [
      { title: { name1: 'value1' } },
      { newTitle: { name5: 'value5' } }
    ],
    category2: [
      { title: { name3: 'value3' } },
      { title: { name4: 'value4' } }
    ]
  });

尝试过以下写法但未解决:

const titleVar = 'newTitle';
const nameVar = 'name5';
const valueVar = 'value5';

// 写法1
obj.current[ctg][index][titleVar] = { [nameVar]: valueVar };

// 写法2
obj.current = {
    ...obj.current,
    [ctg]: [
        ...obj.current[ctg].slice(0, index),
        {
            ...obj.current[ctg][index],
            [titleVar]: { [nameVar]: valueVar }
        },
        ...obj.current[ctg].slice(index + 1)
    ]
};

// 写法3
const temp = {...obj.current[ctg][index],
               [titleVar]: { [nameVar]: valueVar } };
obj.current = temp;

错误原因分析

  • 写法3完全错误:直接将obj.current赋值为单个元素的对象,彻底替换了原有的整个嵌套结构,导致除新添加的newTitle外,其他所有属性全部丢失。
  • 写法1和写法2逻辑本身正确,若失效大概率是ctg或index变量取值错误(比如index指向了错误元素、ctg字符串拼写错误),或是混淆了useRef特性——useRef更新不会触发组件重渲染,若通过UI判断结果,可能看不到更新后的状态。

正确解决方案

方案1:直接修改原对象(适合无需UI更新的场景)

确认ctg和index取值正确后,直接给目标元素添加新属性即可,不会覆盖原有title:

const titleVar = 'newTitle';
const nameVar = 'name5';
const valueVar = 'value5';
const ctg = 'category1';
const index = 1; // 对应category1中的第二个元素

obj.current[ctg][index][titleVar] = { [nameVar]: valueVar };

方案2:创建新嵌套结构(若需触发UI更新,建议改用useState)

如果更新需要反映到UI上,不推荐用useRef存储驱动UI的状态,应改用useState。若坚持使用useRef,可通过创建新结构的方式更新:

const titleVar = 'newTitle';
const nameVar = 'name5';
const valueVar = 'value5';
const ctg = 'category1';
const index = 1;

obj.current = {
  ...obj.current,
  [ctg]: obj.current[ctg].map((item, i) => 
    i === index ? { ...item, [titleVar]: { [nameVar]: valueVar } } : item
  )
};

关键注意事项

  1. 绝对避免写法3的错误赋值,会直接破坏原有数据结构。
  2. 若用useRef存储状态,其更新不会触发组件重渲染,如需UI同步,必须改用useState。
  3. 写法1/2失效时,优先检查ctg和index的取值是否准确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 06:35:30