[英]Infinite Loop with useEffect - ReactJS
I have a problem when using the useEffect hook, it is generating an infinite loop.我在使用 useEffect 钩子时遇到问题,它生成了一个无限循环。
I have a list that is loaded as soon as the page is assembled and should also be updated when a new record is found in "developers" state.我有一个在页面组装后立即加载的列表,并且在“开发人员”状态下发现新记录时也应该更新。
See the code:看代码:
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)
If I remove the developer dependency on the second parameter of useEffect, the loop does not happen, however, the list is not updated when a new record is found.如果我删除开发人员对 useEffect 的第二个参数的依赖,则不会发生循环,但是,在找到新记录时不会更新列表。 If I insert "developers" in the second parameter of useEffect, the list is updated automatically, however, it goes into an infinite loop.
如果我在 useEffect 的第二个参数中插入“developers”,列表会自动更新,但是,它会进入无限循环。
What am I doing wrong?我究竟做错了什么?
complete code (with component): https://gist.github.com/fredarend/c571d2b2fd88c734997a757bac6ab766完整代码(带组件): https : //gist.github.com/fredarend/c571d2b2fd88c734997a757bac6ab766
The dependencies for useEffect
use reference equality, not deep equality. useEffect
的依赖使用引用相等,而不是深度相等。 (If you need deep equality comparison for some reason, take a look at use-deep-compare-effect
.) (如果出于某种原因需要进行深度相等比较,请查看
use-deep-compare-effect
。)
The API call always returns a new array object, so its reference/identity is not the same as it was earlier, triggering useEffect
to fire the effect again, etc. API 调用总是返回一个新的数组对象,因此它的引用/标识与之前的不一样,触发
useEffect
再次触发效果等。
Given that nothing else ever calls setDevelopers
, ie there's no way for developers
to change unless it was from the API call triggered by the effect, there's really no actual need to have developers
as a dependency to useEffect
;鉴于没有其他任何东西调用
setDevelopers
,即developers
无法更改,除非它来自效果触发的 API 调用,因此实际上没有实际需要让developers
作为useEffect
的依赖useEffect
; you can just have an empty array as deps: useEffect(() => ..., [])
.你可以有一个空数组作为 deps:
useEffect(() => ..., [])
。 The effect will only be called exactly once.该效果只会被调用一次。
EDIT: Following the comment clarification,编辑:在评论澄清之后,
I register a developer in the form on the left [...] I would like the list to be updated as soon as a new dev is registered.
我在左侧的表格中注册了一名开发人员 [...] 我希望在注册新开发人员后立即更新列表。
This is one way to do things:这是做事的一种方式:
The idea here is that developers
is only ever automatically loaded on component mount.这里的想法是
developers
只会在组件安装时自动加载。 When the user adds a new developer via the AddDeveloperForm
, we opportunistically update the local developers
state while we're posting the new developer to the backend.当用户通过
AddDeveloperForm
添加新开发developers
时,我们会在将新开发人员发布到后端的同时机会性地更新本地developers
状态。 Whether or not posting fails, we reload the list from the backend to ensure we have the freshest real state.无论发布是否失败,我们都会从后端重新加载列表以确保我们拥有最新的真实状态。
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} />
</>
);
};
The problem is that your getDevelopers
function, calls your setDevelopers
function, which updates your developers
variable.问题是您的
getDevelopers
函数调用了setDevelopers
函数,该函数更新了您的developers
变量。 When your developers
variable is updated, it triggers the useEffect
function当您的
developers
变量更新时,它会触发useEffect
函数
useEffect(() => {
getDevelopers();
}, [developers]);
because developers
is one of the dependencies passed to it and the process starts over.因为
developers
是传递给它的依赖项之一,并且该过程重新开始。
Every time a variable within the array, which is passed as the second argument to useEffect, gets updated, the useEffect
function gets triggered每次更新数组中作为 useEffect 的第二个参数的变量时,都会触发
useEffect
函数
Use an empty array []
in the second parameter of the useEffect.在 useEffect 的第二个参数中使用空数组
[]
。 This causes the code inside to run only on mount of the parent component.这会导致内部代码仅在父组件的安装上运行。
useEffect(() => {
getDevelopers();
}, []);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.