简体   繁体   中英

React : Updating and then accessing state after a network request in useEffect hook. State remains stale

Im trying to update and reference hasError state field inside of the initialization function of my component in order to control if a redirect happens after successful initialization or if error gets displayed.

Here is a condensed version of the issue:

const [hasError, setHasError] = useState(false);

useEffect(() => {
  initialize();
}, []);

async function initialize(){
  try {
    await networkRequest();
  } catch (err) {
    setHasError(true);
  }
  console.log(hasError);  // <- is still false
  if(!hasError){
    redirect()  // <- causes redirect even with error
  }
}

function networkRequest() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject();
    }, 1000);
  });
}

The initialization function should only be called once on component mount which is why I'm passing [] to useEffect . Passing [hasError] to useEffect also doesn't make sense since I don't want initialization to run everytime hasError updates.

I have seen people recommend using useReducer but that seems hacky since I'm already using Redux on this component and I'll need to use 2 different dispatch instances then.

How is a use case like this typically handled?

You will have to create another useEffect hook that "listens" for changes to hasError . setHasError in this case is asynchronous, so the new value won't be available to you immediately.

I don't know what the rest of your component looks like, but it sounds like you should have some sort of isLoading state that will be used to display a loading message, then once your request finishes and it fails, you render what you need, or if it succeeds, you redirect .

Here's an example:

function App() {
  const [isLoading, setIsLoading] = useState(true);
  const [hasError, setHasError] = useState(false);

  useEffect(() => {
    (async () => {
      try {
        await networkRequest();
        isLoading(false);
      } catch (error) {
        setHasError(error);
        isLoading(false);
      }
    })()
  }, [])

  useEffect(() => {
    if (!isLoading && !hasError) {
      redirect();
    }
  }, [isLoading, hasError]);

  if (isLoading) { return "Loading"; }
  
  // else, do whatever you need to do here
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM