Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Hooks - useEffect fires even though the state did not change

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.

like image 539
Enrique Moreno Tent Avatar asked Feb 28 '19 10:02

Enrique Moreno Tent


People also ask

Does useEffect run on state change?

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.

Why does useEffect keep running?

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.

Does useEffect fire on Mount?

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.

How do you fix the infinite loop inside useEffect React Hooks?

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.


2 Answers

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: [...]

like image 130
r g Avatar answered Sep 22 '22 06:09

r g


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.

like image 32
Baroudi Safwen Avatar answered Sep 19 '22 06:09

Baroudi Safwen