Gavin-walsh
Gavin-walsh

Reputation: 109

React Hook useEffect has a missing dependency. How do I fix this error?

React Hook useEffect has a missing dependency.

Line 92:4: React Hook useEffect has a missing dependency: 'getMoviesData'. Either include it or remove the dependency array react-hooks/exhaustive-deps

Can someone tell me how to fix this error? I'm sure it's something very simple but any help would be greatly appreciated!

function App() {

// * MOVIE API *


//State 
const [movies, setMovies] = useState([])
const [topMovies, setTopMovies] = useState([])
const [kidsMovies, setKidsMovies] = useState([])
const [setKidsTv] = useState([])
//kidsTv
const [setTvShows] = useState([])
//TvShows
const [kidsTvSeries, setKidsTvSeries] = useState([])




//API URL 
const url = 'https://api.themoviedb.org/3/discover/movie?api_key=&with_genres=28/';
const tvUrl = 'https://api.themoviedb.org/3/tv/popular?api_key=8&language=en-US&page=1';
const kidsMovieURL = 'https://api.themoviedb.org/3/discover/movie?api_key=8&certification_country=US&certification.lte=G&with_genres=16&include_adult=false&sort_by=popularity.desc';
const kidsTvURL = 'https://api.themoviedb.org/3/tv/popular?api_key=8&language=en-US&page=1&with_genres=16&include_adult=false&sort_by=popularity.desc';
const topPicks = 'https://api.themoviedb.org/3/movie/top_rated?api_key=&language=en-US&page=1';
const kidsSeries = 'https://api.themoviedb.org/3/discover/tv?api_key=1f7c961ae4f02a23e0968d449c15bc98&with_genres=10762'

//Async function to fetch API
async function getMoviesData (url, tvUrl, topPicks, kidsMovieURL, kidsTvUrl, kidsSeries) {

  await fetch(url).then(res => res.json()).then(data => setMovies(data.results))
  await fetch(topPicks).then(res => res.json()).then(data => setTopMovies(data.results))
  await fetch(tvUrl).then(res => res.json()).then(data => setTvShows(data.results))
  await fetch(kidsMovieURL).then(res => res.json()).then(data => setKidsMovies(data.results))
  await fetch(kidsTvUrl).then(res => res.json()).then(data => setKidsTv(data.results))
  await fetch(kidsSeries).then(res => res.json()).then(data => setKidsTvSeries(data.results))
}



//Use Effect 
 useEffect(() => { 
  getMoviesData(url, tvUrl, topPicks, kidsMovieURL, kidsTvURL, kidsSeries);

}, [])


  return (

    <div className='app'>

      <div className="header">
        <Header Home={Home} Movies={Movies} Kids={Kids} Music={lazyMusic} movies={movies} topMovies={topMovies} kidsMovies={kidsMovies} kidsTvSeries={kidsTvSeries} />
      </div>

      <div className="music-player">
        <MusicPlayer />
      </div>
  

    </div>
  )
}

export default App

Upvotes: 0

Views: 99

Answers (4)

Anh Le Hoang
Anh Le Hoang

Reputation: 349

You should move getMoviesData func inside callback of useEffect like this:

//Use Effect 
 useEffect(() => { 
  //Async function to fetch API
  async function getMoviesData (url, tvUrl, topPicks, kidsMovieURL, kidsTvUrl, kidsSeries) {
    await fetch(url).then(res => res.json()).then(data => setMovies(data.results))
    await fetch(topPicks).then(res => res.json()).then(data => setTopMovies(data.results))
    await fetch(tvUrl).then(res => res.json()).then(data => setTvShows(data.results))
    await fetch(kidsMovieURL).then(res => res.json()).then(data => setKidsMovies(data.results))
    await fetch(kidsTvUrl).then(res => res.json()).then(data => setKidsTv(data.results))
    await fetch(kidsSeries).then(res => res.json()).then(data => setKidsTvSeries(data.results))
  }
  getMoviesData(url, tvUrl, topPicks, kidsMovieURL, kidsTvURL, kidsSeries);

}, [])

Or another way, you can put getMoviesData func outside useEffect, but you need add useCallback for getMoviesData like this:

    const getMoviesData = useCallback(async (url, tvUrl, topPicks, kidsMovieURL, kidsTvUrl, kidsSeries) => {
      await fetch(url).then(res => res.json()).then(data => setMovies(data.results))
      await fetch(topPicks).then(res => res.json()).then(data => setTopMovies(data.results))
      await fetch(tvUrl).then(res => res.json()).then(data => setTvShows(data.results))
      await fetch(kidsMovieURL).then(res => res.json()).then(data => setKidsMovies(data.results))
      await fetch(kidsTvUrl).then(res => res.json()).then(data => setKidsTv(data.results))
      await fetch(kidsSeries).then(res => res.json()).then(data => setKidsTvSeries(data.results))
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [])
    
    useEffect(() => { 
      getMoviesData(url, tvUrl, topPicks, kidsMovieURL, kidsTvURL, kidsSeries);
    }, [getMoviesData])

Upvotes: 0

Ali Nauman
Ali Nauman

Reputation: 1677

When using useEffect, one thing to keep in mind is that any state variable or function that is defined inside the component and used inside the effect function (the 1st argument passed to useEffect) should be included in the dependency array (the 2nd argument).

In your component, you are using the getMoviesData function inside the useEffect hook, but you have not included that in the dependency array. That is why you are getting the linter warning. To fix this, you just have to add the function in the dependency array. So your useEffect hook will become this:

useEffect(() => { 
  getMoviesData(url, tvUrl, topPicks, kidsMovieURL, kidsTvURL, kidsSeries);
}, [getMoviesData])

However, this creates a problem - this means that whenever the getMoviesData function is recreated, the effect will run once again. Since this function is updating the state, it will cause the component to re-render, which will then cause this function to be re-created, which in turn will cause the effect to run again, creating an infinite loop.

To solve this, you have a few options:

  1. Move the getMoviesData inside the useEffect's effect function (if you are not using it outside the useEffect hook)
  2. Move it outside the component (if you are not interacting with state or any other component methods)
  3. Wrap it with useCallback to memoize the function reference (if you are using the function outside the useEffect)

In your case, you need option #1.

useEffect(() => {
  function getMoviesData (url, tvUrl, topPicks, kidsMovieURL, kidsTvUrl, kidsSeries) {
    fetch(url).then(res => res.json()).then(data => setMovies(data.results))
    fetch(topPicks).then(res => res.json()).then(data => setTopMovies(data.results))
    fetch(tvUrl).then(res => res.json()).then(data => setTvShows(data.results))
    fetch(kidsMovieURL).then(res => res.json()).then(data => setKidsMovies(data.results))
    fetch(kidsTvUrl).then(res => res.json()).then(data => setKidsTv(data.results))
    fetch(kidsSeries).then(res => res.json()).then(data => setKidsTvSeries(data.results))
  }

  getMoviesData(url, tvUrl, topPicks, kidsMovieURL, kidsTvURL, kidsSeries);
}, [setMovies, setTopMovies, setKidsMovies, setKidsTv, setKidsTvSeries])

Upvotes: 1

Dulaj Ariyaratne
Dulaj Ariyaratne

Reputation: 1108

You just have to memorize the function using useCallback and add the getMoviesData to the dependency array of the useEffect.

  const getMoviesData = useCallback(async () => {
    await fetch(url).then(res => res.json()).then(data => setMovies(data.results))
    await fetch(topPicks).then(res => res.json()).then(data => setTopMovies(data.results))
    await fetch(tvUrl).then(res => res.json()).then(data => setTvShows(data.results))
    await fetch(kidsMovieURL).then(res => res.json()).then(data => setKidsMovies(data.results))
    await fetch(kidsTvUrl).then(res => res.json()).then(data => setKidsTv(data.results))
    await fetch(kidsSeries).then(res => res.json()).then(data => setKidsTvSeries(data.results))
    }, [])

    useEffect(() => { 
      getMoviesData(url, tvUrl, topPicks, kidsMovieURL, kidsTvURL, kidsSeries);
    
    }, [getMoviesData])

Upvotes: 1

Zhminko Roman
Zhminko Roman

Reputation: 24

Mayve you could try something like that (using useCallback):

const getMoviesData = useCallback(() => { /* your code */ }, []);

Upvotes: -1

Related Questions