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

如何防止React中ref值在重渲染时被意外修改?

问题解决:阻止ref对象自动同步初始值

问题场景

开发嵌套复选框列表时,使用ref对象bodyOriginal存储数据库返回的初始值,以此判断内容是否修改并控制保存按钮的激活状态。已确认该ref仅在数据库请求函数中修改且仅执行一次,但点击复选框时出现异常:

  • 首次点击功能正常,再次点击时bodyOriginal的值自动与最新的body同步,导致修改判断逻辑失效
  • 直接执行JSON.stringify(item) !== JSON.stringify(bodyOriginal.current[index])时结果始终为false,bodyOriginal会自动和body同步,尝试useCallback、useMemo均无效

点击复选框的处理函数:

const handleCheckboxGroup = useCallback((event, index, optionIndex) => {
const original = JSON.stringify(bodyOriginal.current[index]);
setBody(prev =>
  prev.map((item, indexPrev) => {
    if (indexPrev === index) {
      item.options[optionIndex].checked = event.target.checked;
      item.active = JSON.stringify(item) !== original; // 此处判断失效
    }
    return item;
  })
);
}, []);

核心原因

bodyOriginal存储的是初始数据的内存引用,而非独立的副本。在setBody回调中直接修改prev状态里的item对象时,实际上是在修改和bodyOriginal指向同一内存地址的对象,导致bodyOriginal的值被意外篡改。

解决方案

1. 深拷贝初始数据到ref

获取数据库数据后,对初始数据进行深拷贝,确保bodyOriginal存储的是完全独立的对象,与后续状态中的对象无引用关联:

// 数据库请求示例
const fetchInitialData = async () => {
  const initialData = await api.get('/your-data');
  // 用JSON序列化实现深拷贝(适合无特殊类型的数据)
  bodyOriginal.current = JSON.parse(JSON.stringify(initialData));
  setBody(initialData);
};

如果数据包含Date、函数等特殊类型,建议使用专门的深拷贝工具(如lodash的_.cloneDeep)。

2. Immutable 方式更新状态

修改状态时不直接修改原对象,而是创建新的对象层级,保证状态更新是不可变的:

const handleCheckboxGroup = useCallback((event, index, optionIndex) => {
  const originalItem = bodyOriginal.current[index];
  setBody(prev =>
    prev.map((item, indexPrev) => {
      if (indexPrev !== index) return item;
      
      // 创建新的options数组,替换目标选项的checked状态
      const newOptions = [...item.options];
      newOptions[optionIndex] = {
        ...newOptions[optionIndex],
        checked: event.target.checked
      };
      
      // 创建新的item对象,计算修改状态
      const updatedItem = {
        ...item,
        options: newOptions,
        active: JSON.stringify({...item, options: newOptions}) !== JSON.stringify(originalItem)
      };
      
      return updatedItem;
    })
  );
}, []);

3. 优化修改判断逻辑(可选)

频繁使用JSON.stringify会有性能开销,可在初始化时给每个项保存初始状态快照,或单独跟踪每个项的修改状态,避免重复序列化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 06:55:15