user967451
user967451

Reputation:

Prevent useEffect hook from running on ComponentDidMount()

This code runs when name is changed (as it should) but it also runs when the component first loads. How can I have it run only on subsequent changes to name and not the first time the default value is set?

const [name, setName] = useState('');

useEffect(() => {
  alert('Hi ' + name);
}, [name]);

Upvotes: 3

Views: 1190

Answers (3)

jonidelv
jonidelv

Reputation: 663

This is causing the custom hook to re-run multiples times because you are re-creating a new array in the array of dependencies [callback, ...dependencies] I'd change it like so:

import { useEffect, useRef } from 'react'

function useEffectSkipFirst(callback, dependencies) {
  const firstRenderRef = useRef(true)

  useEffect(() => {
    if (firstRenderRef.current) {
      firstRenderRef.current = false
      return
    }
    callback()
  }, dependencies)
}

export default useEffectSkipFirst

Upvotes: 0

Drew Reese
Drew Reese

Reputation: 203099

Using a ref you can track the first render, set to false after the first render.

const firstRenderRef = useRef(true);
const [name, setName] = useState('');

useEffect(() => {
  if (firstRenderRef.current) {
    firstRenderRef.current = false;
  } else {
    alert('Hi ' + name);
  }
}, [name]);

I'd factor this into a custom hook though

const useSkipFirstEffect = (callback, dependencies) => {
  const firstRenderRef = useRef(true);

  useEffect(() => {
    if (firstRenderRef.current) {
      firstRenderRef.current = false;
    } else {
      callback();
    }
  }, [callback, ...dependencies]);
};

Usage:

useSkipFirstEffect(() => {
  alert('SkipFirstEffect: Hi ' + name);
}, [name]);

Edit useEffect skip first render

Upvotes: 4

Atin Singh
Atin Singh

Reputation: 3690

There are some ways of skipping effect on initial render(like ref and using a variable). What I generally use and found the most simplest way is using the return of useEffect. It seems to me this is a bit hackish way but it works -

const [name, setName] = useState('');

useEffect(() => {
  //don't do anything on initial render
  return () => {
      alert('Hi ' + name);
   }
}, [name]);

Now this will run only when dependency name changes. I am not sure if it's recommended but it always worked for me without any problems. Leaving here in case it helps.

NOTE:: This will also run on component unmount change. To prevent that you can just use a check.

Upvotes: 1

Related Questions