re-fetching data in react using useeffect

The culprit is in this function. Changing state twice (one each for movieNo , pageNo) causes the page to render twice.

 function handleClick(e) {
  e.preventDefault();
  setMovieNo(Math.floor(Math.random() * 20));
  setPageNo(Math.floor(Math.random() * 500 + 1));
 }

Complete Sample Code to reproduce problem

import React, { useState, useEffect } from "react";
import axios from "axios";

const Movie = () => {
  const [pageNo, setPageNo] = useState(1);
  const [movieNo, setMovieNo] = useState(1);
  const [movie, setMovie] = useState("");
  const [isLoading, setIsLoading] = useState(true);
  const [imageUrl, setImageUrl] = useState("https://image.tmdb.org/t/p/");

  function handleClick(e) {
    e.preventDefault();
    setMovieNo(Math.floor(Math.random() * 20));
    setPageNo(Math.floor(Math.random() * 500 + 1));
  }

  async function fetchData(page) {
    const result = await axios(
      `https://api.themoviedb.org/3/discover/movie?api_key=a035c9128c767a8b70c9413632d63cd0&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=${page}&vote_average.gte=1.0`
    );
    setMovie(result.data.results);
    setIsLoading(false);
  }

  useEffect(() => {
    fetchData(pageNo);
  }, [pageNo]);

  return (
    <div>
      <p>{isLoading ? "" : movie[movieNo].title}</p>
      <button onClick={handleClick}>next</button>
    </div>
  );
};

export default Movie;

FIX HERE

  1. Combined state in single object
 const [rank, setRank] = useState({ pageNo: 1, movieNo: 1 });

  setRank({
      pageNo: Math.floor(Math.random() * 500 + 1),
      movieNo: Math.floor(Math.random() * 20)
    });

Complete code after fix.

import React, { useState, useEffect } from "react";
import axios from "axios";

const Movie = () => {
  const [rank, setRank] = useState({ pageNo: 1, movieNo: 1 });
  const [movie, setMovie] = useState("");
  const [isLoading, setIsLoading] = useState(true);
  const [imageUrl, setImageUrl] = useState("https://image.tmdb.org/t/p/");

  function handleClick(e) {
    e.preventDefault();
    setRank({
      pageNo: Math.floor(Math.random() * 500 + 1),
      movieNo: Math.floor(Math.random() * 20)
    });
  }

  async function fetchData(page) {
    setIsLoading(true);
    const result = await axios(
      `https://api.themoviedb.org/3/discover/movie?api_key=a035c9128c767a8b70c9413632d63cd0&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=${page}&vote_average.gte=1.0`
    );
    setMovie(result.data.results);
    setIsLoading(false);
  }

  useEffect(() => {
    fetchData(rank.pageNo);
  }, [rank]);

  return (
    <div>
      <p>{isLoading ? "loading..." : movie[rank.movieNo].title}</p>
      <button onClick={handleClick}>next</button>
    </div>
  );
};

export default Movie;

In summary, there is nothing wrong with useEffect. Changing state too many times is causing your component to render many times. Try to merge all these conditions in a single state so that its easier to manage.

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top