简体   繁体   中英

How should I fix eslint warning (React Hook useEffect has a missing dependency) and a loop caused by the warning?

In following codes, eslint will give a warning.

Line 24:6:  React Hook useEffect has a missing dependency: 'fetchPosts'. Either include it or remove the dependency array  react-hooks/exhaustive-deps
import { useState, useEffect } from 'react';
import { useLocation } from "react-router-dom";
import { Layout } from './Layout';
import { TwitterPost, reloadTwitterEmbedTemplate } from '../TwitterPost';
import '../../styles/pages/TimelinePage.css'
import axios from 'axios';

export const TimelinePage = () => {
  const [posts, setPosts] = useState([]);
  const [page, setPage] = useState(1);
  const location = useLocation();

  const fetchPosts = async () => {
    const res = await axios.get('/api/posts', { params: { page: page } });
    setPosts(posts.concat(res.data));
    reloadTwitterEmbedTemplate();
    setPage(page + 1);
  };

  useEffect(() => {
    if (location.pathname !== '/') return;

    fetchPosts();
  }, [location]);

  const postTemplates = posts.map((post: any) => {
    if (post.media_name === 'twitter') return <TwitterPost mediaUserScreenName={post.media_user_screen_name} mediaPostId={post.media_post_id} />;
    return null;
  });

  return(
    <Layout body={
      <div id="timeline">
        <div>{postTemplates}</div>
        <div className="show-more-box">
          <button type="button" className="show-more-button" onClick={fetchPosts}>show more</button>
        </div>
      </div>
    } />
  );
};

I fixed the warning by adding fetchPosts . Then I followed eslint instructions using useCallback and adding variables used in fetchPosts to deps. This change causes a loop. How should I fix the loop and eslint warning?

import { useState, useEffect, useCallback } from 'react';
import { useLocation } from "react-router-dom";
import { Layout } from './Layout';
import { TwitterPost, reloadTwitterEmbedTemplate } from '../TwitterPost';
import '../../styles/pages/TimelinePage.css'
import axios from 'axios';

export const TimelinePage = () => {
  const [posts, setPosts] = useState([]);
  const [page, setPage] = useState(1);
  const location = useLocation();

  const fetchPosts = useCallback(async () => {
    const res = await axios.get('/api/posts', { params: { page: page } });
    setPosts(posts.concat(res.data));
    reloadTwitterEmbedTemplate();
    setPage(page + 1);
  }, [page, posts]);

  useEffect(() => {
    if (location.pathname !== '/') return;

    fetchPosts();
  }, [location, fetchPosts]);

  const postTemplates = posts.map((post: any) => {
    if (post.media_name === 'twitter') return <TwitterPost mediaUserScreenName={post.media_user_screen_name} mediaPostId={post.media_post_id} />;
    return null;
  });

  return(
    <Layout body={
      <div id="timeline">
        <div>{postTemplates}</div>
        <div className="show-more-box">
          <button type="button" className="show-more-button" onClick={fetchPosts}>show more</button>
        </div>
      </div>
    } />
  );
};

I highly recommend this article to really understand what's going on when you use the useEffect hook. It talks, among other things, about your exact problem and ways to solve it. That said, you should move the function inside the useEffect callback, something like:

export const TimelinePage = () => {
  /* ... */

  useEffect(() => {
    if (location.pathname !== '/') return;
    const fetchPosts = async () => {
        const res = await axios.get('/api/posts', { params: { page: page } });
        setPosts(posts.concat(res.data));
        reloadTwitterEmbedTemplate();
        setPage(page + 1);
    }
    fetchPosts();
  }, [location]);

  /* ... */
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM