FAQ: The Effect Hook - Clean Up Effects

This community-built FAQ covers the “Clean Up Effects” exercise from the lesson “The Effect Hook”.

Paths and Courses
This exercise can be found in the following Codecademy content:

Learn React

FAQs on the exercise Clean Up Effects

There are currently no frequently asked questions associated with this exercise – that’s where you come in! You can contribute to this section by offering your own questions, answers, or clarifications on this exercise. Ask or answer a question by clicking reply (reply) below.

If you’ve had an “aha” moment about the concepts, formatting, syntax, or anything else with this exercise, consider sharing those insights! Teaching others and answering their questions is one of the best ways to learn and stay sharp.

Join the Discussion. Help a fellow learner on their journey.

Ask or answer a question about this exercise by clicking reply (reply) below!
You can also find further discussion and get answers to your questions over in Language Help.

Agree with a comment or answer? Like (like) to up-vote the contribution!

Need broader help or resources? Head to Language Help and Tips and Resources. If you are wanting feedback or inspiration for a project, check out Projects.

Looking for motivation to keep learning? Join our wider discussions in Community

Learn more about how to use this guide.

Found a bug? Report it online, or post in Bug Reporting

Have a question about your account or billing? Reach out to our customer support team!

None of the above? Find out where to ask other questions here!

Hi to whoever finds their way here,

This learning module React hooks is bugged.

The lesson will not pass despite having an identical solution to “view solution”

I’m sure this will be fixed soon as long as you report the bug.

import React, { useState, useEffect } from ‘react’;

export default function Counter() {

const [clickCount, setClickCount] = useState(0);

const increment = () => setClickCount((prev) => prev + 1);

useEffect(() => {

document.addEventListener(‘mousedown’, increment);

return () => {

document.removeEventListener(‘mousedown’, increment);

};

});

return (

<h1>Document Clicks: {clickCount}</h1>

);

5 Likes

Thanks for sharing. My code was accepted, and the lesson passed for “3. Clean Up Effects” module, so looks like someone addressed the bug.

BUT I see that nothing happens in the rendered window. It shows only “Document Clicks: 0” and nothing happens when I click anywhere in the browser window. Anyone else having this problem?

Nothing happens when I run it in Chrome or Firefox. Copied your code in (which looks identical to mine, to my newbie eyes), same result. Even when I try ‘keydown’ instead of ‘mousedown’ the browser doesn’t respond or change:

useEffect(() => {
    document.addEventListener('keydown',increment);
    return () => {
      document.removeEventListener('keydown',increment);
    };
  });

My original code that passes the lesson checkmark and allows me to continue but seems to be nonfunctional:

import React, { useState, useEffect } from 'react';
export default function Counter() {
  const [clickCount, setClickCount] = useState(0);
  // your code here
  const increment = () =>{
    setClickCount((prev) => prevCount+1);
  })
  useEffect(() => {
    document.addEventListener('mousedown',increment);
    return () => {
      document.removeEventListener('mousedown',increment);
    };
  });
  return (
      <h1>Document Clicks: {clickCount}</h1>
  );
}
2 Likes

Same issue here, nothing happens.

On a different note to the comments above…

The Effect Cleanup lesson shows how to avoid ever growing stacks of event listeners by using a clean-up function in the callback’s return statement.

This is due to the fact that ‘addEventListeners()’ method allows setting up multiple identical listeners on a single document element.

useEffect(() => {
    document.addEventListener('mousedown', increment);
    return () => {
      document.removeEventListener('mousedown', increment);
    };
  });

The alternative approach would be to use the other method of creating event listeners. An event listener created using the following method is overwritten every single time, and doesn’t require any clean-up solution.

 useEffect(()=>{
    document.onmousedown = increment;
  });
7 Likes

Have a look at this line of your code
setClickCount((prev) => prevCount+1);
It should be
setClickCount((prev) => prev + 1);

2 Likes

Thanks for pointing that “prev” argument error out, @mtrtmk! With the change, I’m still getting a frozen screen that is unresponsive to document clicks. Were you able to get a functioning Counter.js in the lesson, which responds to document clicks with functioning event listeners?

The code as-is seems to be returning some kind of error that’s not reported back in JS console, and results in a frozen app that doesn’t update. I think this because editing anything, including the h1 element’s “Document Clicked:” text after the first render does not reflect in the displayed h1. I also try adding buttons, h2 (in an effort to try to get an event listener to work in this environment), but nothing shows up.

The h1 text will update at the beginning of the lesson at part "1."but after adding the useEffect nothing updates.

Finally, in the DOM elements > event listeners window of Chrome DevTools, under “mousedown”, 4 identical, blank event listeners appear, none of which contain any of the language added in Counter.js. See screenshot. Clicking on “clean-up-effects:7” leads to an empty file in sources, with no shown “global listeners”. Are functioning event listeners usually visible somewhere in Chrome DevTools?

What am I missing?

My code, edited after mtrtmk’s helpful comment:

import React, { useState, useEffect } from 'react';
export default function Counter() {
  const [clickCount, setClickCount] = useState(0);
  // your code here
  const increment = () =>{
    setClickCount((prev) => prev+1);
  })
  useEffect(() => {
    document.addEventListener('mousedown',increment);
    return () => {
      document.removeEventListener('mousedown',increment);
    };
  });
  return (
      <h1>Document Clicks: {clickCount}</h1>
  );
}

DevTools listed event listeners screenshot:

I think your problem lies in the snippet:

const increment = () =>{
    setClickCount((prev) => prev+1);
  })

You have an extra closing parenthesis. Remove it and use a semi-colon instead.

const increment = () =>{
    setClickCount((prev) => prev+1);
  };

I think that should fix the issues you are seeing.

1 Like

import React, { useState, useEffect } from ‘react’;

export default function Counter() {
const [clickCount, setClickCount] = useState(0);

const increment = () => {
setClickCount((prev) => prev + 1));
}
// your code here
useEffect(() =>{
document.addEventListener(‘mousedown’, increment);
return() => {
document.removeEventListener(‘mousedown’, increment);
};
});
return (

Document Clicks: {clickCount}


);
}

I am seeing nothing in the HTML window of this exercise no

Document Clicks: {clickCount}

is not being rendered at all. What gives??

dont sweat it, it happens to everyone. just a bug. your codes good though.

Would anyone help me out figuring whats the point of adding the removeEventListener as a cleanup function ?
Like could anyone articulate the real use-cases of a cleanup function for a useEffect hook

Random question regarding the following:

useEffect(()=>{
    document.addEventListener('mousedown', increment)
  return ()=>{
    document.removeEventListener('mousedown',increment)
  };
})

Why is there a “return ()=>” in front of the document.removeEventListener(‘mousedown’,increment)
but there isnt one in front of document.addEventListener(‘mousedown’, increment).
Seems like such a dumb question but I cant seem to articulate why one explicitly has a return and the other doesnt.

Hello egghead777!
From what I understand, the callback function doesn’t need to return something to do something, it just does it that’s why the first eventlistener doesn’t need to have a return. You can check about how callback functions work https://developer.mozilla.org/en-US/docs/Glossary/Callback_function

Also, React expects that the return of the callback function is a cleanup function.

The useEffect expects you pass in it a callback function that does something for us and that returns the cleanup function

useEffect (

   //Callback function that does something for us
   ()=>{  document.addEventListener('mousedown', increment)

             //This callback function returns the cleanup function 
              returns () => { document.removeEventListener('mousedown',increment) }

   }

)

i hope that helped you!

Why would we want to add and remove the event after every single render? Would it not be better to pass the empty array argument to tell the code to only fire on mount and unmount?

 useEffect(() => {
    document.addEventListener('mousedown',increment);
    return () => {
      document.removeEventListener('mousedown',increment);
    }
  },[]);
2 Likes

Can anyone explain why the code does not work with curly brackets around { prev + 1 } in the increment function?

export default function Counter() {
const [clickCount, setClickCount] = useState(0);

  useEffect(() => {
       document.addEventListener('mousedown', increment);
       return () => {
           document.removeEventListener('mousedown', increment);
      };
   });

   // your code here
  const increment = () => {
      setClickCount((prev) => {prev + 1})
  }

  return (
      <h1>Document Clicks: {clickCount}</h1>
  );

}

setClickCount is a state setter. When it is called, it expects something to be returned so that it can update the state.
If you do:

const increment = () => {
    setClickCount((prev) => prev + 1);
  };

then, prev + 1 is being implicitly returned by the arrow function.

If you use curly braces { } and wish to return something, then you must do so explicitly by using the return keyword i.e.

const increment = () => {
    setClickCount((prev) => {return prev + 1;} );
  };
3 Likes

Thank you! That makes perfect sense

Hi,

If we use the onmousedown property, it looks like we don’t need to clean the event listener then?

useEffect(
() => { document.onmousedown = increment; }
);

So this way we don’t need to use the return statement right?

Can someone explain what exactly is happening with setClickCount((prev) => prev + 1)? I have no idea whats happening here so needed to view the solution. And where was prev defined? Did we learn about it in a previous lesson?

In the exercise, we initialize clickCount to 0 and declare setClickCount as being the setter which can change the value of clickCount.

const [clickCount, setClickCount] = useState(0);

We can use setClickCount in two ways. Firstly, if we simply provide a value to this setter, then it will replace the current value of clickCount with the new value. e.g.

setClickCount(7);
// This will set clickCount to be 7

The second way is used when we want to preserve the existing old value or want to use the old value in some calculation to arrive at a new value, then the state setter function allows us this flexibility. The state setter is able to recognize that it is being passed a function instead of a value. All we need to do is just pick a parameter name and the state setter will automatically pass the previous value as the argument.
In our case, we have picked prev as the parameter name. There is nothing special about the name prev. We could have picked a different name, but prev is a good choice as it reminds us of the word previous. We could have picked abc as the parameter name, but that would be a poor choice in terms of readability. We should pick names that help the reader understand the code, rather than picking random names.

setClickCount((prev) => prev + 1)

// prev is the previous value of clickCount. 
// We add 1 to the previous value and implicitly return this value.
// The state setter then assigns this new value to clickCount
// e.g. If previous value of clickCount was 7, then the above
// code will set clickCount to be 8.

In the documentation, see
https://reactjs.org/docs/hooks-reference.html#functional-updates

1 Like