DEV Community

Omar Moataz Attia
Omar Moataz Attia

Posted on • Updated on

React Rapid Fire: How to Wait for useState to Execute?

Image description

Ever wanted useState to update before you continue executing the rest of your code? When we used class components, we had a very useful callback on setState that allowed you to execute code after the state had updated. Let's look at some code just so you know what I'm talking about.

class Home extends React.Component {
  state = {
    counter: 1,
  };

  increment = () => {
    this.setState(
      (state: State) => ({
        counter: state.counter + 1,
      }),
      () => {
        console.log(this.state.counter);
      }
    );
  };

  render() {
    return <div onClick={this.increment}>{this.state.counter} </div>;
  }
}
Enter fullscreen mode Exit fullscreen mode

Here, we are passing a callback to setState so that we're able to access the update counter right after the state update and here, we're guaranteed to have it be updated but what if we want to do the same thing with functional components and hooks.

Well, there isn't a direct alternative that has the same level of convenience but we do have an option in React hooks to the rescue: useEffect.

useEffect is one of those hooks that can be fairly called a jack of all trades but a master of none. It's not really the perfect fit for componentDidMount, componentDidUpdate, or componentWillUnmount but the advantage is that it can replace all of them I guess.

Here, we can use useEffect to listen for that state change and execute the code we wanted to execute in the callback. However, in this case, we're not really forcing react to update the state right away like we used to with class components but rather, we're listening for a change so that we can execute our code when it eventually happens. Let's look at the code

const Home: NextPage = () => {
  const [counter, setCounter] = useState(1);

  useEffect(() => {
    // here I am guaranteed to get the updated counter
    // since I waited for it to change.
    console.log(counter);
    // here we added counter to the dependency array to
    // listen for changes to that state variable.
  }, [counter]);

  const handleClick = () => {
    setCounter(counter => counter + 1);
  }

  return <div onClick={handleClick}> {counter} </div>
};

export default Home;
Enter fullscreen mode Exit fullscreen mode

There is one difference between the 2 implementations to look at here:

useEffect will listen to every change to counter and execute the effect unlike the class component implementation which would only execute the code we want in the specific situation we're in. In this case, the callback in class components is more accurate with regards to when it executes.

If you would like to know more about useEffect, you can refer to the docs

If you'd like to dive deeper into hooks and writing your own hooks, I wrote an article explaining just that here

Top comments (0)