Reputation:
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
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
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]);
Upvotes: 4
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