Dot
Dot

Reputation: 11

React does not set state immediately

I have just started learning reactjs. I am trying to set the state with an object received from the API, and then display the results from the state. When I try to display the results, it shows state object undefined. When I query the API for a second time, it sets the state to the object received from API.

const SearchByName = () => {
  const [recipes, setRecipes] = useState({
    recipesObj: {},
    loding: false,
  });


  const fetchData = async () => {
    try {
      setRecipes({ loading: true });

      const res = await axios.get(`url_to_API`);

      console.log(res.data) // prints returned object from API

      setRecipes({ recipesObj: res.data, loading: false });

      console.log(recipes.recipesObj); // empty object

    } catch (err) {
      console.error(err);
    }
  };
};

 const onSubmit = (e) => {
    e.preventDefault();
    fetchData();
    setSearchStr('');
  };

Upvotes: 0

Views: 72

Answers (3)

Chukwuemeka Maduekwe
Chukwuemeka Maduekwe

Reputation: 8586

In react we have lifecycle components your code is correct but what missing is useEffect for functional components

  import {useEffect, useState } from "react"

 const SearchByName = () => {
     const [recipes, setRecipes] = useState({
        recipesObj: {},
        loding: false,
  });

 useEffect(()=>{
       // useEffect can access fetchData anytime
      fetchData()
 },[])

  const fetchData = async () => {
    try {
      setRecipes({ loading: true });

      const res = await axios.get(`url_to_API`);

      console.log(res.data) // prints returned object from API

      setRecipes({ recipesObj: res.data, loading: false });

      console.log(recipes.recipesObj);

    } catch (err) {
       console.error(err);
    }
  };
};

It should work now, the only difference is the useEffect lifecycle hook

Upvotes: 0

Ako
Ako

Reputation: 196

Remember set state in react is and Async function

To know more about what is state in react please check this Llink in react docs .

React state in both functional and class based is an async function, to handle what you want you should check your state in an useEffect or outside of that related function that setState fired.

const SomeComponent = () => {
  const [dataFetched,setDataFetched] = React.useState(false);
  const mockTheRequest = () => {
    // make the request and set the state
    setDataFetched(true)
  }
    
   React.useEffect(()=>{
      // fire your xhr request when component rendered.
      mockTheRequest()
    },[])
    
  React.useEffect(() => {
    if(dataFetched){
      // on data fetched
      console.log("state", dataFetched)
    }
  },[dataFetched])
  
  return(
    <div>
      <span>
        is data fetched? {dataFetched}
      </span>
    </div> 
  )
}

Upvotes: 0

Naren
Naren

Reputation: 4480

You're replacing the state with { loading: true }, here recipes.recipesObj will become undefined. you need to prepend the earlier state. Try changing like this or you can use different state to manage the loading and data

const fetchData = async () => {
    try {
      setRecipes({ ...recipes, loading: true }); // Here was the problem
      or setRecipes({ recipesObj: {}, loading: true });

      const res = await axios.get(`url_to_API`);

      console.log(res.data) // prints returned object from API

      setRecipes({ recipesObj: res.data, loading: false });

      console.log(recipes.recipesObj);

    } catch (err) {
      console.error(err);
    }
  };
};

Upvotes: 1

Related Questions