0

when I try to get some data from my backend API using axios, and set the state after I've gotten the result for some reason the state is not updated and when I try to use the state it will only show me an empty array. but what's so interesting is that when I console.log(res.data) it will show me my array of lists with no problem, so I guess the problem is with the setCategories() state function. What am I doing wrong?

const Home = (props) => {
  const [categories, setCategories] = useState([]);
  useEffect(() => {
    getCats();
  }, []);

  const getCats = async () => {
    const data = await axios.get(`${myUrl}/allItems`, {
      withCredentials: true,
    });
    const cats = await data.data;
    console.log(cats); //this one works perfectly
    setCategories(cats);
    console.log(categories) //this one doesn'nt work which means the setState didn't work
  };


  return (
    <>
      <div className="card-div mt-5">
        {categories.map((cat) => {
          <li>{cat.name}</li>;
        })}
      </div>
    </>
  );
};

  • Does this answer your question? [useState set method not reflecting change immediately](https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately) – cbr Jan 07 '21 at 11:40
  • You just set the categories to cats `setCategories(cats)` but then log the [stale closure](https://dmitripavlutin.com/react-hooks-stale-closures/) categories: `console.log(categories)` why not just log cats instead: `console.log(cats)` – HMR Jan 07 '21 at 12:09
  • the log is not important to me, what's important is I want to render the ```categories``` list to the DOM but when I use the ```map()``` function it doesn't do anything because it is undefined at that time – LeonSnipez Jan 07 '21 at 12:11

2 Answers2

1

the state is set asynchronously, so the data is not updated instantly. that's why you are not getting the output on console.log(categories) right after setCategories(cats);

here is a small example of asynchronous behaviour of useState state update:

Link to working example: stackblitz

import React, { useEffect, useState } from "react";
import "./style.css";
import axios from "axios";
const url = "https://jsonplaceholder.typicode.com/users";
export default function App() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    axios.get(url).then(result => {
      console.log("1. when data is fetched sucessfully: ", result.data);
      setUsers(result.data);
      console.log("2. Just after setting state: ", users);
    });
  }, []);

  // secons useEffect for logging out upadated todos useState
  useEffect(() => {
    console.log("todos upadated: ", users);
  }, [users]);
  return (
    <div>
      <h1>Hello StackBlitz!</h1>
      <p>Start editing to see some magic happen :)</p>
      {users.map(user => (
        <p>{user.name}</p>
      ))}
    </div>
  );
}

Here is what is happening in the above example:

enter image description here

You can see the flow of data fetching and async update of state.

Ketan Ramteke
  • 10,183
  • 2
  • 21
  • 41
0

The useState function is asynchronous, so you will never get the new state in the same function, the best way is to use it in another function or useEffect. Example:

 useEffect(() => {
    console.log(categories);
  }, [categories]);

Mvrocha
  • 393
  • 3
  • 14