react更改多层对象变量的方法

以下是我的测试组件中:

import React, { useEffect, useState } from 'react';

export default function Home() {
  const [obj, setObj] = useState({ a: { t: 1 }, b: { t: 333 } })
  { console.log(1111, '重新执行') }
  const ceshi = () => {
    setObj(pre => ({
      ...pre,
      a: {
        ...pre.a,
        t: pre.a.t + 1
      }
    }));
    /*
  setObj(pre => {
      const newObj = { ...pre }
      newObj.a.t = 55;
      return newObj;
    });
  */
    // const objNew = JSON.parse(JSON.stringify(obj));
    // objNew.a.t = objNew.a.t + 1;
    // setObj(objNew);
  }
  useEffect(() => {
    console.log("🚀 ~ Home ~ obj:", obj)
  }, [obj])

  useEffect(() => {
    console.log("🚀 ~ Home ~ 具体字段a:", obj.a)
  }, [obj.a])
  useEffect(() => {
    console.log("🚀 ~ Home ~ 具体字段b:", obj.b)
  }, [obj.b])
  return <>
    {console.log(1111, '重新渲染')}
    <div onClick={ceshi}>ceshi-{obj.a.t}-{obj.b.t}</div>
  </>;
}
  1. 使用JSON.parse(JSON.stringify(obj))深度克隆
    深度克隆每个key引用都变,以上三个useEffect监听都能监听到
    但是性能差,还可能数据丢失
    如果我子组件b只传入了obj.b,即使b组件使用了memo;这样修改a的时候b组件也会重新执行
setObj(pre => ({
      ...pre,
      a: {
        ...pre.a,
        t: pre.a.t + 1
      }
    }));

这种只更新了对象中的a,所以obj.b监听不到
3.

setObj(pre => {
      const newObj = { ...pre }
      newObj.a.t = 55;
      return newObj;
 });

这种只更新了obj.a.t, obj.a和obj.b都监听不到,但是页面会更新(以为obj变了组件会重新执行)
4. 使用 Immer

import { produce } from 'immer';

setObj(produce(draft => {
  draft.a.t += 1;
  // b 自动保持原样,Immer 会正确处理
}));

总结,我一般使用2或者3比较多,具体更新整个key,哪个key,还是更新最里面的字段,需要根据业务场景来定;
比如说我子组件a监听属性a,b组件监听属性b,那我希望父组件更新的a属性的时候,b组件监听的b不要执行,那就需要父元素只改a的引用;

posted @ 2026-02-03 16:50  ฅ˙-˙ฅ  阅读(3)  评论(3)    收藏  举报