0

Based on this popular answer https://stackoverflow.com/a/19014495 I have the following code.

I am trying to understand why "remove effect" is never logged.

function useWindowSize(){
    const [size, setSize] = useState([0,0]);
    useLayoutEffect(() => {
        console.log("use effect");
        function updateSize(){
            setSize([window.innerWidth, window.innerHeight]);
        }
        window.addEventListener('resize', updateSize);
        updateSize();
        return () => {
            console.log("remove effect");
            window.removeEventListener('resize', updateSize);
        }
    }, []);
    return size;
}

This custom hook is used in a function component

function InfiniteScroll () {
    const [width, height] = useWindowSize();
    // rest of code should be irrelevant
}

Based on the React documentation an empty array as second argument for the built in hooks means that the effect is used and then cleaned up only once. https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects. I was surprised therefore that this is used in this code snippet because the event listener would be removed immediately. However in testing I discovered that whilst "use effect" is logged "remove effect"is not. Why? What other concept am I missing?

user1849962
  • 1,273
  • 1
  • 11
  • 16

3 Answers3

1

Cleanup effect with an empty dependency array runs on component unmount.

It also mentioned in the docs you shared:

If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run. This isn’t handled as a special case — it follows directly from how the dependencies array always works.

So having conditional rendering will show the log

const [show,toggle] = useReducer(p=>!p,true);

// Will log "remove effect" on show === false
<>
  <button onClick={toggle}>toggle</button>
  {show && <InfiniteScroll />}
</>

For more info see useEffect use cases.

Dennis Vash
  • 50,196
  • 9
  • 100
  • 118
  • Thanks, I did not understand what "mount" meant then. I had assumed "mounting" and "un-mounting" was the same as "render" and "removing previous render effect". P.S Only started with React yesterday. – user1849962 Feb 07 '21 at 15:33
0

The return part in the useEffect hook is a clean-up process that is only happening when the targeted component is unmounting, That is what you're missing try to navigate away or destroy this component and you should see the log message.

Mohamed Wagih
  • 1,246
  • 6
  • 17
0

I already tried the snippet you showed and I think it's working as expected and showing the remove effect log once. according to the react docs,

If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run.

so on mounting this component the listener already added to window once, and then as long as you are still in the same component you have access to the event listener. on unmount the remove effect will be logged as well. you have to unmount the component to see the remove effect log