Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why React hook useEffect runs endlessly?

Tags:

reactjs

I created a project with create-react-app,
and I am trying React hooks,
in below example,
the sentence console.log(articles) runs endlessly:

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;

Why is it?How to handle it?

https://i.sstatic.net/SHLjh.gif

like image 704
zwl1619 Avatar asked Oct 18 '25 19:10

zwl1619


2 Answers

React useEffect compares the second argument with it previous value, articles in your case. But result of comparing objects in javascript is always false, try to compare [] === [] in your browser console you will get false. So the solution is to compare not the whole object, but articles.lenght

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

useEffect(() => {
    getArticleList().then(res => {
       setArticles(res.data.article_list);
        console.log(articles);  
    });
},[articles.length]);
like image 73
Pavel Avatar answered Oct 20 '25 10:10

Pavel


It is simply because you cannot compare two array (which are simply) objects in JavaScript using ===. Here what you are basically doing is comparing the previous value of articleName to current value of articleName, which will always return false. Since

That comparison by reference basically checks to see if the objects given refer to the same location in memory.

Here its not, so each time re-rendering occurs. The solution is to pass a constant like array length or if you want a tight check then create a hash from all element in the array and compare them on each render.

like image 27
sijinzac Avatar answered Oct 20 '25 09:10

sijinzac