React useState not updating state

534 views Asked by At

I'm training React Hooks with a movie app and I now face with a problem. When I click in a button in the Header component, there should be a change of state by cleaning the itemsList array. The code is actually prepared for a Load More button, that will add more items to this array, when the API request used with other component (not present yet). The problem is that the array is not been cleaned and when some button is cliche the items from que API Request are added to it.

This is the App.js file

import React, { useState } from "react";
import axios from "axios";
import Header from "./Containers/Header";

export default function App() {
  const [values, setValues] = useState({
    msdb: "API_CODE",
    page: 1,
    totalPages: 0,
    listType: "popular",
    mode: "movie",
    itemsList: [],
    searchFiled: "",
    loading: false,
    error: false
  });
  const { msdb, page, totalPages, listType, mode, itemsList, searchFiled, loading, error } = values;

  const modeSelection = (event) => {
    let modeType = "";
    let selectedMode = event.target.innerText;
    console.log(selectedMode);
    if (selectedMode === "Movies") {
      modeType = "movie";
    } else if (selectedMode === "Series") {
      modeType = "tv";
    }
    setValues((prevValues) => {
      return { ...prevValues, mode: modeType, itemsList: [] };
    });
    let endPoint = `https://api.themoviedb.org/3/${mode}/${listType}?api_key=${msdb}&page=${page}`;
    fetchItems(endPoint);
  };

  const fetchItems = (endPoint) => {
    axios
      .get(endPoint)
      .then((response) => {
        const newItemsList = [...itemsList];
        const newItems = response.data.results;
        if (newItems) {
          setValues((prevValues) => {
            return {
              ...prevValues,
              page: response.data.page,
              itemsList: [...newItemsList, ...newItems],
              loading: false,
              totalPages: response.data.total_pages
            };
          });
        }
      })
      .catch((error) => {
        setValues({ ...values, error: true });
        console.log(error);
      });
  };

  return (
    <div className="App">
      <Header mode={modeSelection} />
    </div>
  );
}

And this is the Header.js file

import React from "react";
import "./Header.css";
import { NavLink } from "react-router-dom";

export default function Header(props) {
  return (
    <div>
      
        <div className="top-center">
          <NavLink to="/movies" onClick={props.mode} className="ch-button">
            Movies
          </NavLink>
          <NavLink to="/series" onClick={props.mode} className="ch-button">
            Series
          </NavLink>
        </div>
        
    </div>
  );
}

So what I would like to be the result is, when clicking on Header component buttons, the itemsList array should be cleaned and the API request would populate it again. Remember that the axios method is already prepared for a Load More Button in another component and, in this case, it will add more Items to the array. Should there be a useEffect somewhere? Thank you

1

There are 1 answers

2
Anastasiia Solop On BEST ANSWER

The problem is about the asynchronous nature of setState. You correctly use prevState to set a new one, but in the 'fetchItems' when setting new items, you get old ones from current state and not prevState. This way the state is not yet updated with empty array when you use it for setting new items. You can try

        if (newItems) {
          setValues((prevValues) => {
            return {
              ...prevValues,
              page: response.data.page,
              itemsList: [...prevState.itemsList, ...newItems],
              loading: false,
              totalPages: response.data.total_pages
            };
          });
        }