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>
</>;
}
- 使用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的引用;

浙公网安备 33010602011771号