Search code examples
javascriptreactjsreact-hooksaxiossetstate

How do I access latest state in useEffect (when updating state) without including dependency


I'm trying to access the latest state in other setState function, cant figure out the correct way of doing it for a functional component

without accessing the latest state setMoviesListset state as undefined and causes issues

state

  const [movies, setMoviesList] = useState();
  const [currentGenre, setcurrentGenre] = useState();
  const [page, setPage] = useState(1);
  const [genreList, setGenreList] = useState();
  const [nextPage, setNextPage] = useState(false);
  const [previousMovieList, setPreviousMovieList] = useState();
  useEffect(() => {
    async function getMovies(currentGenre, page) {
      if (currentGenre) {
        const data = await rawAxios.get(
          `https://api.themoviedb.org/3/discover/movie?api_key=f4872214e631fc876cb43e6e30b7e731&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=${page}&with_genres=${currentGenre}`
        );

        setPreviousMovieList((previousMovieList) => {
          if (!previousMovieList) return [data.data];
          else {
            if (nextPage) {
              console.log(previousMovieList);
              setNextPage(false);
              return [...previousMovieList, data.data];
            }
          }
        });
        setMoviesList(previousMovieList.results);
      } else {
        const data = await rawAxios.get(
          `https://api.themoviedb.org/3/discover/movie?api_key=f4872214e631fc876cb43e6e30b7e731&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=${page}`
        );

          if (!previousMovieList) {
            console.log('!previousMovieList', previousMovieList); 
            console.log('!data', data.data); 
            setPreviousMovieList(previousMovieList)
          } else {
            if (nextPage) {
              console.log('else', previousMovieList);
              setNextPage(false);
              setPreviousMovieList([...previousMovieList, data.data])
              
              // return [...previousMovieList, data.data];
            }
          }
        setMoviesList(previousMovieList.results);   
      }
    }
    getMovies(currentGenre, page);
  }, [currentGenre, page, setMoviesList, nextPage]);

want to access latest previousMovieList here

setMoviesList(previousMovieList.results);


Solution

  • You need to include previousMovieList in your useEffect dependency array as follows:

    useEffect(()=>
       {...}, 
       [currentGenre, page, setMoviesList, nextPage, previousMovieList]
    );
    

    Without including it, you will have a stale closure and latest value will not be reflected in your function. This is causing the initial previousMovieList value of undefined to never update within your useEffect logic.

    If you dont want it in your useEffect deps, you can use a ref:

    const previousMovieList = useRef();
    //then in your useEffect
    setMoviesList(previousMovieList.current.results)
    //and to set it
    previousMovieList.current = ... // whatever you want to store
    

    Or you can do something like this:

        setPreviousMovieList((previousMovieList) => {
          if (!previousMovieList) return [data.data];
          else {
            if (nextPage) {
              setNextPage(false);
              return [...previousMovieList, data.data];
            }
          }
          setMoviesList(previousMovieList.results);
        });
    

    Basically move setMoviesList to within the setPreviousMovieList function where you do have access to previousMovieList.

    Kind of hard to tell what you're trying to do, but generally when you want to store the previous value of state, you would use the ref approach. Like usePrevious for example