[英]Infinite Loop with useEffect - ReactJS
我在使用 useEffect 钩子时遇到问题,它生成了一个无限循环。
我有一个在页面组装后立即加载的列表,并且在“开发人员”状态下发现新记录时也应该更新。
看代码:
const [developers, setDevelopers] = useState<DevelopersData[]>([]);
const getDevelopers = async () => {
await api.get('/developers').then(response => {
setDevelopers(response.data);
});
};
// This way, the loop does not happen
useEffect(() => {
getDevelopers();
}, []);
// This way, infinte loop
useEffect(() => {
getDevelopers();
}, [developers]);
console.log(developers)
如果我删除开发人员对 useEffect 的第二个参数的依赖,则不会发生循环,但是,在找到新记录时不会更新列表。 如果我在 useEffect 的第二个参数中插入“developers”,列表会自动更新,但是,它会进入无限循环。
我究竟做错了什么?
完整代码(带组件): https : //gist.github.com/fredarend/c571d2b2fd88c734997a757bac6ab766
useEffect
的依赖使用引用相等,而不是深度相等。 (如果出于某种原因需要进行深度相等比较,请查看use-deep-compare-effect
。)
API 调用总是返回一个新的数组对象,因此它的引用/标识与之前的不一样,触发useEffect
再次触发效果等。
鉴于没有其他任何东西调用setDevelopers
,即developers
无法更改,除非它来自效果触发的 API 调用,因此实际上没有实际需要让developers
作为useEffect
的依赖useEffect
; 你可以有一个空数组作为 deps: useEffect(() => ..., [])
。 该效果只会被调用一次。
编辑:在评论澄清之后,
我在左侧的表格中注册了一名开发人员 [...] 我希望在注册新开发人员后立即更新列表。
这是做事的一种方式:
这里的想法是developers
只会在组件安装时自动加载。 当用户通过AddDeveloperForm
添加新开发developers
时,我们会在将新开发人员发布到后端的同时机会性地更新本地developers
状态。 无论发布是否失败,我们都会从后端重新加载列表以确保我们拥有最新的真实状态。
const DevList: React.FC = () => {
const [developers, setDevelopers] = useState<DevelopersData[]>([]);
const getDevelopers = useCallback(async () => {
await api.get("/developers").then((response) => {
setDevelopers(response.data);
});
}, [setDevelopers]);
useEffect(() => {
getDevelopers();
}, [getDevelopers]);
const onAddDeveloper = useCallback(
async (newDeveloper) => {
const newDevelopers = developers.concat([newDeveloper]);
setDevelopers(newDevelopers);
try {
await postNewDeveloperToAPI(newDeveloper); // TODO: Implement me
} catch (e) {
alert("Oops, failed posting developer information...");
}
getDevelopers();
},
[developers],
);
return (
<>
<AddDeveloperForm onAddDeveloper={onAddDeveloper} />
<DeveloperList developers={developers} />
</>
);
};
问题是您的getDevelopers
函数调用了setDevelopers
函数,该函数更新了您的developers
变量。 当您的developers
变量更新时,它会触发useEffect
函数
useEffect(() => {
getDevelopers();
}, [developers]);
因为developers
是传递给它的依赖项之一,并且该过程重新开始。
每次更新数组中作为 useEffect 的第二个参数的变量时,都会触发useEffect
函数
在 useEffect 的第二个参数中使用空数组[]
。 这会导致内部代码仅在父组件的安装上运行。
useEffect(() => {
getDevelopers();
}, []);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.