2

I am forcing below code to run through the catch block where it sets getFoodCategoriesFailed to true and after that when it goes to finally block it still shows getFoodCategoriesFailed as false which is its initial value. Can someone point it out what I am doing wrong and help me fix it.

const [getFoodCategoriesFailed, setGetFoodCategoriesFailed] = useState(false);

const getCategories = async (url) => {
  const { request } = await requestor.get({ url });

  request.then((response) => {
    setFoodCategories(response);
    setGetFoodCategoriesFailed(false);
  }).catch(() => {
    setFoodCategories(undefined);
    setGetFoodCategoriesFailed(true);
  }).finally(() => {
    onFoodCategoriesRetrieved(getFoodCategoriesFailed, foodCategories?.food_categories);
  });
};

useEffect(() => {
  const url = "xyz";
  getCategories(url);
}, [foodCategories]);

CodeBreaker
  • 95
  • 4
  • 12

2 Answers2

0

useState does not change synchronously

Is useState synchronous?

If you want to use useState synchronously, use the code below

import { useState, useRef, useEffect } from 'react';

export default function useStateCallback(initialState) {
  const [state, setState] = useState(initialState);
  const cbRef = useRef(null); // mutable ref to store current callback

  // eslint-disable-next-line no-shadow
  const setStateCallback = (state, cb) => {
    cbRef.current = cb; // store passed callback to ref
    setState(state);
  };

  useEffect(() => {
    // cb.current is `null` on initial render, so we only execute cb on state *updates*
    if (cbRef.current) {
      cbRef.current(state);
      cbRef.current = null; // reset callback after execution
    }
  }, [state]);

  return [state, setStateCallback];
}

  • So after adding above code, do I just need to update below line of code? ``` const [getFoodCategoriesFailed, setGetFoodCategoriesFailed] = useStateCallback(false); ``` – CodeBreaker Oct 22 '20 at 07:43
  • `const [state, setState] = useStateCallback(0);` `const onClick= () => setState(prev => prev + 1, data => console.log(data))` – kyounghwan01 Oct 22 '20 at 11:17
0

I'm not an expert so apologies if this doesn't help, but ... there's a couple of things I might try:

  1. Think about whether it might make sense to move onFoodCategoriesRetrieved into the (or as a new) useEffect call (and add getFoodCategoriesFailed to the dependency list).

  2. Something like:

const getCategories = async (url) => {
  const { request } = await requestor.get({ url });
  let localFoodCategories = undefined;
  let localGetFoodCategoriesFailed = true;
  
  request.then((response) => {
    localFoodCategories = response;
    localGetFoodCategoriesFailed = false;
  }).catch(() => {
  }).finally(() => {
    setFoodCategories(localFoodCategories);
    setGetFoodCategoriesFailed(localGetFoodCategoriesFailed);
    onFoodCategoriesRetrieved(localGetFoodCategoriesFailed, localFoodCategories?.food_categories);
  });
};
Ben Stephens
  • 3,303
  • 1
  • 4
  • 8