Search code examples
reactjsaxiosreact-hooksuse-effectuse-state

React cannot set state inside useEffect does not update state in the current cycle but updates state in the next cycle. What could be causing this?


I am using the useEffect hook for a get request using axios and consequently updating the state with some of the received data. This is my useEffect hook and the function inside:

const [expressions, setExpressions] = useState(expressionData.data);
const getFilteredExp = () => {
    console.log(catFilter);
    let config = {
      method: 'get',
      url: `/expressions/category/${catFilter}`,
      headers: {}
    };
    axios(config)
      .then((response) => {
        console.log(response.data);
        const newExp = response.data.payload.data;
        console.log(expressions);
        setExpressions(newExp);
        console.log(expressions);
      })
      .catch((err) => {
        console.error(err);
      })
  }

useEffect(() => {
  if (!catFilter) {
    setExpressions(expressionData.data)
    console.log(expressionData.data);
  }
  else {
    getFilteredExp();
   }
}, [catFilter])

catFilter is also a state variable. My expressions state variable is not updated directly after the setExpressions call but one render cycle after. Not sure how to fix this.The console logs inside the getFilteredExp function should highlight my problem perfectly. These console logs should show my problem Everytime I change the category filter (catFilter state variable), the page is re-rendered and the previous get request's results are updated in the state. Ideally, the logs should return with 5 items after the get request returns with an array of 5 items. This is clearly not shown in the console log.

Additionally, even though my state is updated a render-late, my page content that depends on the expressions state variable is not being updated and remains in its default state.

Any help would be much appreciated and I am sorry if my question is not very clear or follow some requirements, I am relatively new to this.


Solution

  • The 2 console.logs here will display the same value for expressions, because they are referencing the same copy of expressions:

    console.log(expressions);
    setExpressions(newExp);
    console.log(expressions);
    

    If you want to see the changed value of expressions, you can add a useEffect() that triggers after expressions has had a chance to change:

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

    I'm not sure if there's enough info here to give a specific solution to the other problem. Add more info if you are still stuck.