微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

奇怪的useEffect无限循环

如何解决奇怪的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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?