Himanshu Poddar
Himanshu Poddar

Reputation: 7779

React Hook useEffect has a missing dependency: updateFunction

I have this code, where I am using useEffect to update my page with the infinite scroll. However while compiling the same, I see this error

src\components\News.js
  Line 40:6:  React Hook useEffect has missing dependencies: 'props.category' and 'updateNews'. Either include them or remove the dependency array  react-hooks/exhaustive-deps

But when I am including this function in the dependency array [page, props.category, updateNews] I am getting another error

Line 17:9:  The 'updateNews' function makes the dependencies of useEffect Hook (at line 40) change on every render. Move it inside the useEffect callback. Alternatively, wrap the definition of 'updateNews' in its own useCallback() Hook  react-hooks/exhaustive-deps

Here is my code : Whenever user scrolls the page number is updated and the use Effect hook is being called, which in turn is calling the updateNews function.

import React, { useEffect, useState } from "react";
import NewsItem from "./NewsItem";
import Spinner from "./Spinner";
import PropTypes from "prop-types";
import InfiniteScroll from "react-infinite-scroll-component";

const News = (props) => {
  const [articles, setArticles] = useState([]);
  const [loading, setLoading] = useState(true);
  const [page, setPage] = useState(1);
  const [totalResults, setTotalResults] = useState(0);

  const capitalizeFirstLetter = (string) => {
    return string.charAt(0).toUpperCase() + string.slice(1);
  };

  const updateNews = async () => {
    props.setProgress(10);
    let goToPage = page;
    const url = `https://newsapi.org/v2/top-headlines?country=${props.country}&category=${props.category}&apiKey=${props.apiKey}&page=${goToPage}&pageSize=${props.pageSize}`;
    props.setProgress(30);
    let data = await fetch(url);
    props.setProgress(50);
    let parsedData = await data.json();
    props.setProgress(70);
    if (parsedData) {
      setArticles(articles.concat(parsedData.articles));
      setLoading(false);
      setPage(page);
      setTotalResults(parsedData.totalResults);
    }
    props.setProgress(100);
  };

  useEffect(() => {
    updateNews();
    // eslint-disable-next-line
    
    document.title = `${capitalizeFirstLetter(props.category)} - NewsMonkey`;
  }, [page, props.category]);

  const fetchMoreData = async () => {
    setPage(page + 1);
  };

  return (
    <>
      <h3 className="text-center" style={{ marginTop: "4%" }}>
        NewsMonkey - Top {`${capitalizeFirstLetter(props.category)}`} Headlines
      </h3>
      {loading && <Spinner />}
      <InfiniteScroll
        dataLength={articles.length}
        next={fetchMoreData}
        hasMore={articles.length < totalResults}
        loader={<Spinner />}
      >
        <div className="container">
          <div className="row">
            {articles.map((element) => {
              return (
                <div className="col-md-4" key={element.url}>
                  <NewsItem
                    title={
                      element && element.title ? element.title.slice(0, 45) : ""
                    }
                    description={
                      element && element.description
                        ? element.description.slice(0, 50)
                        : ""
                    }
                    imageUrl={element.urlToImage}
                    newsUrl={element.url}
                    author={element.author}
                    date={element.publishedAt}
                    source={element.source.name}
                  />
                </div>
              );
            })}
          </div>
        </div>
      </InfiniteScroll>
    </>
  );
};

export default News;

Note : I tried the answer that I was getting as suggestion to this question but that did not work for me.

Upvotes: 0

Views: 1584

Answers (2)

Arnas Savickas
Arnas Savickas

Reputation: 384

Your solution is actually provided inside the error. After including updateNews inside the dependency array, without any memorization on every rerender React will always see updateNews !== updateNews, which is due to the nature of JS (even equally written functions will never be equal to one another).

Wrapping the updateNews function inside useCallback basically allows React to know that this function will be the same on every rerender until one of its dependency array items change.

This should work:

const updateNews = useCallback(async () => {
    props.setProgress(10);
    let goToPage = page;
    const url = `https://newsapi.org/v2/top-headlines?country=${props.country}&category=${props.category}&apiKey=${props.apiKey}&page=${goToPage}&pageSize=${props.pageSize}`;
    props.setProgress(30);
    let data = await fetch(url);
    props.setProgress(50);
    let parsedData = await data.json();
    props.setProgress(70);
    if (parsedData) {
      setArticles(articles.concat(parsedData.articles));
      setLoading(false);
      setPage(page);
      setTotalResults(parsedData.totalResults);
    }
    props.setProgress(100);
  }, [page, props.country, props.category, props.apiKey, props.pageSize]);

  useEffect(() => {
    updateNews();
    // eslint-disable-next-line
    
    document.title = `${capitalizeFirstLetter(props.category)} - NewsMonkey`;
  }, [props.category, updateNews]);

Upvotes: 3

Jimmy Soussan
Jimmy Soussan

Reputation: 722

You can look into this issue for more informations : How to fix missing dependency warning when using useEffect React Hook

But you should probably just move your function inside the useEffect like so :

 useEffect(() => {
   const updateNews = async () => {
     props.setProgress(10);
     let goToPage = page;
      const url = `https://newsapi.org/v2/top-headlines?country=${props.country}&category=${props.category}&apiKey=${props.apiKey}&page=${goToPage}&pageSize=${props.pageSize}`;
      props.setProgress(30);
      let data = await fetch(url);
      props.setProgress(50);
      let parsedData = await data.json();
      props.setProgress(70);
      if (parsedData) {
        setArticles(articles.concat(parsedData.articles));
        setLoading(false);
        setPage(page);
        setTotalResults(parsedData.totalResults);
      }
      props.setProgress(100);
    };
    updateNews();    
    document.title = `${capitalizeFirstLetter(props.category)} - NewsMonkey`;
  }, [page, props.category]);

Upvotes: 1

Related Questions