如何解决奇怪的useEffect无限循环
通过我们用来处理 apiCalls 的钩子看到一些奇怪的事情,其中 api 响应结构的突然变化在我们的应用程序中触发了无限请求循环。我已将其精简到重现错误的基本要求。
import React,{useEffect,useState,useMemo} from 'react';
const mockedApiCall = (resolvedValue,time) =>
new Promise((resolve,reject) => setTimeout(() => resolve(resolvedValue),time));
const useHook = (query) => {
const [error,setError] = useState(null);
const [data,setData] = useState([]);
useEffect(() => {
const asyncoperation = async () => {
const response = await mockedApiCall([],1000);
// Testing something i kNow will fail:
const mappedData = response.data.map(a => a);
// if the above didn't fail we would update data
setData(mappedData);
};
// Clear old errors
setError(null);
// trigger operation
asyncoperation().catch(e => {
console.log('fail');
setError('Some error');
});
},[query]);
return [data,error];
}
const HookIssue = props => {
const [data,error] = useHook({foo: 'bar'}); // Creates infinite loop
//const [data,error] = useHook('foo') // only fails a single time
// Alternative solution that also doesn't create infinite loop
// const query = useMemo(() => ({foo: 'bar'}),[]);
// const [data,error] = useHook(query);
return null;
};
export default HookIssue;
有人知道这里发生了什么吗?这个钩子应该只监听查询变量的变化,但在某些情况下会陷入无限循环。
编辑:为了给这个问题添加一些更奇怪的东西,如果我删除 useEffect 中的两个 setError 调用中的一个(或两个),它也会防止无限循环。
解决方法
之所以会出现此循环,是因为您将对象传递给 useHook()
。对象是引用类型——也就是说,它们不是由它们的值定义的。由于这个原因,以下语句的计算结果为 false:
{ foo: "bar" } === { foo: "bar" }
每次渲染 HookIssue
时,都会创建一个新的 { foo: "bar" }
对象。这被传递给依赖数组中的 useEffect()
,但是因为对象是引用类型 - 每个渲染上的每个对象都有不同的引用 - React 将始终“看到”query
值已更改。
这意味着每次 asyncOperation
完成后,都会导致重新渲染 HookIssue
,从而触发另一个效果。
要解决此问题,您需要将值类型或传递给依赖项数组,或者您需要通过使用 {{} 来“稳定”query
对象1}}。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。