在下面的最小示例中,父组件具有data
属性并将data.value
传递给子组件。我很难理解更新策略到底发生了什么:
const MY_DATAVALUE = {
a: 1,
b: 2
};
const DATA = {
value: MY_DATAVALUE
};
function Child(props) {
useEffect(() => {
console.log("child props changed");
}, [props]);
return <h1>Child</h1>;
}
export default function App() {
const [data, setData] = useState(DATA);
useEffect(() => {
console.log("data changed");
}, [data]);
useEffect(() => {
console.log("data.value changed");
}, [data.value]);
function handleButtonClick() {
const newData = {
value: MY_DATAVALUE
};
setData(newData);
}
return (
<>
<button onClick={handleButtonClick}>Button</button>
<Child value={data.value} />
</>
);
}
(请参阅此Codesandbox(现在,当点击按钮时,我认为会发生以下情况:
应用程序的
handleButtonClick()
被执行,data
-状态现在指向一个新对象。因此,应用程序的第一个useEffect
(检查data
(触发。然而,
data.value
仍然包含相同的引用(对MY_DATAVALUE
(,因此App的第二个useEffect
(检查data.value
(不会触发。
BUT:儿童的useEffect
(检查props
(触发器。为什么?根据父母的说法,data.value
没有改变(否则第二个useEffect
会被触发(。
你能解释一下为什么ChildsuseEffect
会触发吗?我怎么知道道具"真的"变了?我需要单独检查所有道具钥匙吗?非常感谢。
useEffect
依赖项将在我们提供的内容不同的情况下触发更改。如果我们用不同的值传递相同的引用,或者传递不同的引用,就会发生这种情况。
const newData = {
value: MY_DATAVALUE
};
setData(newData);
data
现在指代不同的对象,而value
键指代与以前的值相同的对象。
这意味着,这个钩子将触发:
useEffect(() => {
console.log("data changed");
}, [data]);
虽然这不会触发:
useEffect(() => {
console.log("data.value changed");
}, [data.value]);
到目前为止,这就是您在这两点中解释的内容。
对于子对象,props
对象是每次渲染的新引用。
由于这个原因,这个钩子将始终触发:
useEffect(() => {
console.log("child props changed");
}, [props]);
而这个钩子不会触发:
const MY_DATAVALUE = {
a: 1,
b: 2
};
// In Parent...
<Child value={MY_DATAVALUE} />
// In Child...
useEffect(() => {
console.log("child value changed");
}, [props.value]);