import React,{useEffect,useState} from 'react';
export function App(props) {
let [state,setState]=useState(2);
console.log('outside',state);
useEffect(()=>{
document.querySelector('.btn').addEventListener('click',()=>{
console.log('afterclick',state);
setState(state-1);
})
},[state])
return (
<>
<button className="btn">click me</button>
</>
);
}
the output looks like this(no click of button):
outside 2
the output looks like this(after one click of button):
outside 2
afterclick 2
outside 1
everything works as expected till now, the second click of button is where it gets confusing for me
clearly the value of state now is 1. as ‘outside 1’ is printed in the last line
output (after 2 clicks)
outside 2
afterclick 2
outside 1
afterclick 2 // why is 2 here instead of 1?
outside 1
afterclick 1
outside 0
why is ‘afterclick 2’ printed? instead of ‘afterclick 1’, as the value of state now is 1.
why does it still print 2? this is where my confusion lies. i also do not understand why the two lines above ‘outside 0’, are printed.
any explanation??
do tell me if any clarification is needed.
thank you!
2
Answers
You need to clean up the event listener when value of state is change or component is unmounted, this will correctly handles the state current value.
On the second render (after clicking the button) the
useEffect
will be run again (since it depends onstate
, which has changed) and a new event listener will be attached. The old listener has captured the value ofstate
and it will always log it as2
, while the second listener will always log it as1
(the third as0
and so on…).When attaching event listeners, you should clean them up, like so:
However, a better way to handle button clicking, is to instead use the
onClick
prop, like so:Unless you’re attaching listeners to
window
ordocument
, usingaddEventListener
in React should be a last resort.