I have set up an effect inside my component, which changes the view if another state attribute changes. But for some reason, when the component mounts, the effect is run, even though the value of detailIndex
has not changed.
const EventsSearchList = () => { const [view, setView] = useState('table'); const [detailIndex, setDetailIndex] = useState(null); useEffect(() => { console.log('onMount', detailIndex); // On mount shows "null" }, []); useEffect( a => { console.log('Running effect', detailIndex); // On mount shows "null"!! Should not have run... setView('detail'); }, [detailIndex] ); return <div>123</div>; };
Why is this happening?
UPDATE: In case it is not clear, what I am trying is to run the effect when the component updates because detailIndex
changes. NOT when it mounts.
Use the useEffect hook to listen for state changes in React. You can add the state variables you want to track to the hook's dependencies array and the logic in your useEffect hook will run every time the state variables change.
Changing state will always cause a re-render. By default, useEffect always runs after render has run. This means if you don't include a dependency array when using useEffect to fetch data, and use useState to display it, you will always trigger another render after useEffect runs.
Important: the useEffect hook will always run on mount regardless of if there is anything in its dependency array. We probably don't want to actually run this effect on our data when it's undefined (as it will be on initial render) but rather we want to wait until it is populated from the API call.
To get rid of your infinite loop, simply use an empty dependency array like so: const [count, setCount] = useState(0); //only update the value of 'count' when component is first mounted useEffect(() => { setCount((count) => count + 1); }, []); This will tell React to run useEffect on the first render.
useEffect
from React Hooks is by default executed on every render, but you can use second parameter in function to define when the effect will be executed again. That means that function is always executed on mount. In your situation your second useEffect
will be run on start and when detailIndex
changes.
More info: https://reactjs.org/docs/hooks-effect.html
Source:
Experienced JavaScript developers might notice that the function passed to useEffect is going to be different on every render. [...] You can tell React to skip applying an effect if certain values haven’t changed between re-renders. To do so, pass an array as an optional second argument to useEffect: [...]
In my case, the component kept updating even though I used the second argument in useEffect() and I was printing the argument to make sure it did not change and it did not change. The problem was that I was rendering the component with map() and there cases where the key changed, and if the key changes, for react it is a completely different object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With