1. 如果你的对象结构比较简单,并且你只想对嵌套对象的某个字段进行监听,你可以直接监听该字段的变化,而不是监听整个对象。这样,你可以避免深度比较,简单直接地达到监听效果。
import React, { useState, useEffect } from 'react';
function DeepWatch() {
const [state, setState] = useState({ count: 0, details: { name: 'John', age: 25 } });
// 监听嵌套对象的具体字段变化
useEffect(() => {
console.log('Age changed:', state.details.age);
}, [state.details.age]); // 只监听 age 字段的变化
const updateState = () => {
setState(prevState => ({
...prevState,
details: { ...prevState.details, age: prevState.details.age + 1 }
}));
};
return (
<div>
<p>Count: {state.count}</p>
<p>Name: {state.details.name}</p>
<p>Age: {state.details.age}</p>
<button onClick={updateState}>Increment Age</button>
</div>
);
}
2.如果需要避免每次重新渲染都做深度比较,可以将前一个对象的引用保存在 useRef
中,然后对比当前值与之前的值,只有当值发生变化时才更新状态。
import React, { useState, useEffect, useRef } from 'react';
import isEqual from 'lodash.isequal';
function DeepWatch() {
const [state, setState] = useState({ count: 0, details: { name: 'John', age: 25 } });
const prevStateRef = useRef();
useEffect(() => {
if (!isEqual(state, prevStateRef.current)) {
console.log('state has changed:', state);
prevStateRef.current = state;
}
}, [state]); // 每次 state 变化时执行
const updateState = () => {
setState(prevState => ({
...prevState,
details: { ...prevState.details, age: prevState.details.age + 1 }
}));
};
return (
<div>
<p>Count: {state.count}</p>
<p>Name: {state.details.name}</p>
<p>Age: {state.details.age}</p>
<button onClick={updateState}>Increment Age</button>
</div>
);
}
解释:
- 使用
useRef
存储state
的前一个值。 - 使用
isEqual
比较当前的state
和prevStateRef.current
,只有当它们不同才会执行副作用逻辑。 - 通过
useRef
可以避免在每次useEffect
触发时进行深度比较,从而提高性能。