为什么React hook useEffect无休止地运行?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么React hook useEffect无休止地运行?相关的知识,希望对你有一定的参考价值。

我用create-react-app创建了一个项目, 我正在尝试React钩子, 在下面的例子中, console.log(articles)句子无休止地运行:

import React, {useState, useEffect} from "react"
import {InfiniteScroller} from "react-iscroller";
import axios from "axios";
import './index.less';

function ArticleList() {
    const [articles, setArticles] = useState([]);

    useEffect(() => {
        getArticleList().then(res => {
           setArticles(res.data.article_list);
            console.log(articles);  
        });
    },[articles]);

    const getArticleList = params => {
        return axios.get('/api/articles', params).then(res => {
            return res.data
        }, err => {
            return Promise.reject(err);
        }).catch((error) => {
            return Promise.reject(error);
        });
    };


    let renderCell = (item, index) => {
        return (
            <li key={index} style={{listStyle: "none"}}>
                <div>
                    <span style={{color: "red"}}>{index}</span>
                    {item.content}
                </div>
                {item.image ? <img src={item.image}/> : null}
            </li>
        );
    };

    let onEnd = () => {
        //...
    };


    return (
        <InfiniteScroller
            itemAverageHeight={66}
            containerHeight={window.innerHeight}
            items={articles}
            itemKey="id"
            onRenderCell={renderCell}
            onEnd={onEnd}
        />
    );
}

export default ArticleList;

为什么?如何处理?

https://i.stack.imgur.com/SHLjh.gif

答案

React useEffect将第二个参数与之前的值,您的案例中的文章进行比较。但是在javascript中比较对象的结果总是错误的,尝试在浏览器控制台中比较[] === [],你会得到错误。所以解决方案是比较整个对象,而不是article.lenght

const [articles, setArticles] = useState([]);

useEffect(() => {
    getArticleList().then(res => {
       setArticles(res.data.article_list);
        console.log(articles);  
    });
},[articles.length]);
另一答案

这只是因为您无法使用===比较JavaScript中的两个数组(简单地说)对象。这里你基本上做的是将articleName的先前值与articleName的当前值进行比较,该值将始终返回false。以来

通过引用进行的比较基本上检查给定的对象是否指向内存中的相同位置。

这里不是,所以每次重新渲染都会发生。解决方案是传递一个像数组长度一样的常量,或者如果你想要一个严格的检查,那么从数组中的所有元素创建一个哈希,并在每个渲染上比较它们。

另一答案

上面的答案是在正确的轨道上,但让我补充一点。这是React的useEffect钩子的问题。

这类似于Redux Reducer的工作方式。每次将对象作为第二个参数传入useEffect数组时,它都被视为内存中的不同对象。

例如,如果你打电话

useEffect(() > {}, [{articleName: 'Hello World'}])

然后重新渲染,每次都会再次调用。所以传递文章的长度是绕过这个的一种方法。如果您不希望第二次调用该函数,则可以传入一个空数组作为参数。

另一答案

我遇到了一个数组对象。我发现只是传递[array.length],因为第二个参数不起作用,所以我必须创建第二个状态以跟上array.length并在操作数组时调用setArrayLength。

const = [array, setArray] = useState([]);
const = [arrayLength, setArrayLength] = useState(array.length)

useEffect(() => {
        const fetchData = async () => {
            const result = await axios.get(// whatever you need);
            setArray(result.data)
        };
        fetchData();

    }, [arrayLength]);

const handleArray () => {
   // Do something to array
   setArrayLength(array.length);
}

利用useRef进行了深入的比较,你可以看到代码here。有一个关于egghead的附带视频,但它在付费墙后面。

以上是关于为什么React hook useEffect无休止地运行?的主要内容,如果未能解决你的问题,请参考以下文章

react源码debugger-各个hooks的逻辑实现(useState和useEffect)

react源码debugger-各个hooks的逻辑实现(useState和useEffect)

react源码debugger-各个hooks的逻辑实现(useState和useEffect)

React Hooks --- useState 和 useEffect

useEffect中防抖为什么不起作用?react hooks中如何写防抖?

反应 | React Hook useEffect 缺少依赖项