Categories
React

How to Run the useEffect React Hook Callback Only on State Update?

Spread the love

The useEffect hook lets us watch the values of states and props and do something according to their values.

Sometimes we may only want to run the useEffect callback when a state value has been updated.

In this article, we’ll look at how to only run the useEffect hook callback only when a state value is updated.

Run the useEffect React Hook Callback Only on State Update

To run the useEffect hook callback only when a state is updated, we can create a ref to keep track of when a state is updated.

For instance, we can write:

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

export default function App() {
  const isInitialMount = useRef(true);
  const [count, setCount] = useState(0);

  useEffect(() => {
    if (isInitialMount.current) {
      isInitialMount.current = false;
    } else {
      console.log(count);
    }
  });

  return (
    <form>
      <button onClick={() => setCount((c) => c + 1)}>increment</button>
    </form>
  );
}

We create the isInitialMount ref with the useRef hook which is set to true initially.

Then we create the count state which we want to log only when count is updated.

In the useEffect callback, we check is isInitialMount.current is true .

If it’s true , then we set initialMount.current to false .

Refs are non-reactive, so it won’t cause a re-render of the component.

However, the current value persists across renders.

When isIninitialMount.current is false , we log the value of count .

Below that, we have a button that calls setCount to update the count value when we click it.

Now when we click the increment button, we see count is logged starting when it’s 1, which means it’s updated beyond its initial value.

We can also extract the logic into its own hook.

For instance, we dcan write:

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

const useUpdateEffect = (effect, dependencies = []) => {
  const isInitialMount = useRef(true);

  useEffect(() => {
    if (isInitialMount.current) {
      isInitialMount.current = false;
    } else {
      effect();
    }
  }, dependencies);
};

export default function App() {
  const [count, setCount] = useState(0);

  useUpdateEffect(() => {
    console.log(count);
  }, [count]);

  return (
    <form>
      <button onClick={() => setCount((c) => c + 1)}>increment</button>
    </form>
  );
}

We have the useUpdateEffect hook that takes the effect function, which we want to run when anything in the dependencies array change.

We move the isInitialMount ref to the hook.

And we call useEffect in useUpdateEffect hook instead of the App component.

This lets us reuse the logic anywhere with ease.

Conclusion

We can add a ref to keep track of when a component is updated when running the useEffect callback code we want accordingly when it does.

This lets run the useEffect callback only when the component is updated.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *