DEV Community

Cover image for  How to useEffect vs componentDid/Will-unmount
Rohit Pratti
Rohit Pratti

Posted on • Edited on

How to useEffect vs componentDid/Will-unmount

I was working on a project and I had to close out some modals, and realized there were both Class component modals and Functional component modals that were involved... so I decided for the class component I would use the life cycle methods and use useEffect for the functional components heres what they look like

Lifecycle method

Alt Text

useEffect Method

Alt Text

The Similarities

Let's get the easy stuff out of the way how are they similar..?

thats right!

the handleClick function is the same barring the minor difference of using "const" in the functional component the logic of the actual function is pretty simple, if you click on the modal background or hit the esc key it should call the function that closes the modal.

The Differences

Now whats the difference? its how you handle the event-listeners,
you might notice that in class components if you have an event-listener
in it, and it console.log("hello") and go to you google-developer tools
and checked console, you might notice it console logs it 3 times, this is because you haven't done what I call a clean up listener aka the removeEventListener function call so it doesn't know when to stop listening to the click, once the modal is closed there is no need for the event listener to be active! other wise it would open and close immediately when you tried to open it!

in the useEffect you do this using a "clean-up function" which you can see in the return function, this removes the event listener when the component is no longer rendered,

the equivalent to this in the class component is componentWillUnmount
inside this you can add the clean up function and now the event listener is only active while the modal is open!

pretty fun and simple function that uses some cool features!

Top comments (13)

Collapse
 
pallymore profile image
Yurui Zhang

Hi, in your code handleClick seems to depend on props.closeAddItemModal well first of all this.props probably does not work because it's a function component. Secondly if closeAddItemModal changes it probably will cause issues in this useEffect hook. It's probably better to add it as a dependency of the effect:

useEffect(() => {
  const handleClick = (e) => {
     // your handle click
  };

  document.addEventListener('mousedown', handleClick, false);
  document.addEventListener('keydown', handleClick, false);

  return () => {
    // remove event listeners here
  };
}, [props.closeAddItemModal]);
Collapse
 
brohittv profile image
Rohit Pratti

OHHH AMAZING THANK YOU GOOD CATCH!

Collapse
 
pallymore profile image
Yurui Zhang

I see you've updated the code. I would move the definition of handleClick to the body of that useEffect function (if it is not used elsewhere) so we won't be creating a new handleClick function on each render call. Also it's good to show that we are actually using the dependencies inside the hook directly.

If handleClick is also used in other places, an alternative method to this is to combine this with useCallback

const handleClick = useCallback(() => {
  // same handle click here
}, [props.closeAddItemModal]);

useEffect(() => {
  // same effect
  // different dependencies 
}, [handleClick]);

So if props.closeAddItemModal doesn't change we won't be creating new handleClick funcs and our useEffect hook will be safe.

I'd highly recommend this eslint plugin if you haven't used it npmjs.com/package/eslint-plugin-re...

Thread Thread
 
brohittv profile image
Rohit Pratti

its only used for this functions, so I just move it above the click listener? :o

Thread Thread
 
pallymore profile image
Yurui Zhang

Yea I would do that. So the function is within the same block scope created by the effect.

React could render multiple times (with or without any state / prop changes), it's better to keep dependencies and the code where they are used close.

Thread Thread
 
brohittv profile image
Rohit Pratti

So I made a Util file, and I imported the function and then and callingback to it inside the useEffect, and this works for all my modals except one modal which crashes when I open and close it too many times... any ideas why this could happen?

Thread Thread
 
pallymore profile image
Yurui Zhang

could you share some code?

it sounds like that one modal might have some effects that are not cleaned up properly when closed.

Thread Thread
 
brohittv profile image
Rohit Pratti

Yeah lemme show you

Thread Thread
 
brohittv profile image
Rohit Pratti
Thread Thread
 
brohittv profile image
Rohit Pratti

here is the code for close modal function that I wrote

and this works for all the modals except specifically this one

![thepracticaldev.s3.amazonaws.com/i...]

Thread Thread
 
pallymore profile image
Yurui Zhang • Edited

Right, so in your effect hook, the event listeners are never cleaned up.

you have something like this:

useEffect(() => {
  document.addEventListener('mousedown', (e) => {});

  return () => {
    document.removeEventListener('mousedown', () => {});
  };
}, []);

notice the arrow functions in both document.addEventListenerand removeEventListener calls - you are creating new functions on the fly.

when addEventListener is called here, a new function will be created, and provided as event handler.
when removeEventListener is called, again, another new function will be created, and provided as the reference to which function that needs to be removed from the listeners.

whenever we write () => {} we are creating a new function, and even if the code is exactly the same, javascript will treat them as totally different entities.

To fix this, we should only create the callback once, and pass the reference to that function to all 4 calls:

useEffect(() => {
  // create the event handler and save its reference to const closeModal
  const closeModal = (e) => {
    closeModalFunction(e, closePriceHistoryModal);
  };

  document.addEventListener('mousedown', closeModal); // pass reference to the call
  document.addEventListener('keydown', closeModal); // referencing the same function


  return () => {
    document.removeEventListener('mousedown', closeModal); // same reference
    document.removeEventListener('keydown', closeModal); // same reference
  };
}, [closePriceHistoryModal]);
Thread Thread
 
brohittv profile image
Rohit Pratti

Oh I see... this is the callback you were talking about!!! amazing... the weird thing is it only happens to this specific modal so I didnt notice until now! Let me try this and get back to you

Thread Thread
 
brohittv profile image
Rohit Pratti

AMAZING IT WORKED I added the key down option too.. WOW this lesson was awesome thank you so much... if you ever want free mcdonalds or food I gotchu my friend!