[英]React infinite update loop with useCallback (react-hooks/exhaustive-deps)
Consider the following example that renders a list of iframe
s.考虑以下呈现
iframe
列表的示例。
I'd like to store all the document
s of the rendered iframe
s in frames
.我想将渲染的
iframe
的所有document
存储在frames
。
import React, { useState, useEffect, useCallback } from "react";
import Frame, { FrameContextConsumer } from "react-frame-component";
function MyFrame({ id, document, setDocument }) {
useEffect(() => {
console.log(`Setting the document for ${id}`);
setDocument(id, document);
}, [id, document]); // Caution: Adding `setDocument` to the array causes an infinite update loop!
return <h1>{id}</h1>;
}
export default function App() {
const [frames, setFrames] = useState({
desktop: {
name: "Desktop"
},
mobile: {
name: "Mobile"
}
});
const setFrameDocument = useCallback(
(id, document) => {
setFrames({
...frames,
[id]: {
...frames[id],
document
}
});
},
[frames, setFrames]
);
console.log(frames);
return (
<div className="App">
{Object.keys(frames).map(id => (
<Frame key={id}>
<FrameContextConsumer>
{({ document }) => (
<MyFrame
id={id}
document={document}
setDocument={setFrameDocument}
/>
)}
</FrameContextConsumer>
</Frame>
))}
</div>
);
}
There are two issues here:这里有两个问题:
react-hooks/exhaustive-deps
is complaining that setDocument
is missing in the dependency array. react-hooks/exhaustive-deps
抱怨依赖数组中缺少setDocument
。 But, adding it causing an infinite update loop.frames
shows that only mobile's document
was set.frames
显示只设置了移动设备的document
。 I expect desktop's document
to be set as well.document
也能设置。 How would you fix this?你会如何解决这个问题?
const setFrameDocument = useCallback(
(id, document) => setFrames((frames) => ({
...frames,
[id]: {
...frames[id],
document
}
})),
[]
);
https://codesandbox.io/s/gracious-wright-y8esd https://codesandbox.io/s/gracious-wright-y8esd
The frames object's reference keeps changing due to the state's update.由于状态的更新,frames 对象的引用不断变化。 With the previous implementation (ie the frames object within the dependency array), it would cause a chain reaction that would cause the component to re-render and causing the frames object getting a new reference.
使用之前的实现(即依赖数组中的frames 对象),它会引起连锁反应,导致组件重新渲染并导致frames 对象获得新的引用。 This would go on forever.
这将永远持续下去。
Using only setFrames function (a constant reference), this chain react won't propagate.仅使用 setFrames 函数(常量引用),此链式反应不会传播。 eslint knows setFrames is a constant reference so it won't complain to the user about it missing from the dependency array.
eslint 知道 setFrames 是一个常量引用,因此它不会向用户抱怨它从依赖项数组中丢失。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.