How to implement promise when updating a state in functional React (when using useState hooks)

Viewed 47

I know similar questions are bouncing around the web for quite some time but I still struggle to find a decision for my case.

Now I use functional React with hooks. What I need in this case is to set a state and AFTER the state was set THEN to start the next block of code, maybe like React with classes works:

this.setState({
   someStateFlag: true
}, () => { // then:
   this.someMethod(); // start this method AFTER someStateFlag was updated
});

Here I have created a playground sandbox that demonstrates the issue:

https://codesandbox.io/s/alertdialog-demo-material-ui-forked-6zss6q?file=/demo.tsx

Please push the button to get the confirmation dialog opened. Then confirm with "YES!" and notice the lag. This lag occurs because the loading data method starts before the close dialog flag in state was updated.

const fireTask = () => {
   setOpen(false); // async
   setResult(fetchHugeData()); // starts immediately
};

What I need to achieve is maybe something like using a promise:

const fireTask = () => {
   setOpen(false).then(() => {
      setResult(fetchHugeData());
   });
};

Because the order in my case is important. I need to have dialog closed first (to avoid the lag) and then get the method fired.

And by the way, what would be your approach to implement a loading effect with MUI Backdrop and CircularProgress in this app?

2 Answers

The this.setState callback alternative for React hooks is basically the useEffect hook.
It is a "built-in" React hook which accepts a callback as it's first parameter and then runs it every time the value of any of it's dependencies changes.
The second argument for the hook is the array of dependencies.

Example:

import { useEffect } from 'react';

const fireTask = () => {
   setOpen(false);
};

useEffect(() => {
   if (open) {
      return;
   }
   setResult(fetchHugeData());
}, [open]);

In other words, setResult would run every time the value of open changes,
and only after it has finished changing and a render has occurred.

We use a simple if statement to allow our code to run only when open is false.

Check the documentation for more info.

Related