export default function App() {
const [active, setActive] = useState("");
function handleButtonClick(value) {
if (!active) {
setActive(value);
setTimeout(() => {
setActive("");
console.log(active);
}, 3000);
} else {
let interval = setInterval(() => {
console.log(active);
if (!active) {
setActive(value);
setTimeout(() => {
setActive("");
}, 3000);
clearInterval(interval);
}
}, 0);
}
}
return (
<div
style={{
display: "flex",
flexDirection: "column",
height: "100vh",
justifyContent: "space-between"
}}
>
<div>
<button onClick={() => handleButtonClick("first")}>first</button>
<button onClick={() => handleButtonClick("second")}>second</button>
<button onClick={() => handleButtonClick("third")}>third</button>
</div>
<div>{active.length > 0 && <p>{active} button Clicked</p>}</div>
</div>
);
}
The callback function of setInterval in else case of handleButtonClick function is not having access to updated state, if the setInterval is started and then after that state is updated then the callback function is only having access to previous state but not updated state. How can i fix this
Required functionality
when any button is clicked the active state is set to respective value and then after 3 seconds with setTimeout the state is changed to empty string as i want it to act it as a poppup.
if another button is clicked before 3 seconds then it should wait for current 3 seocnds to complete and should show the respestive button clicked popup
4
Answers
The
active
identifier that the interval callback closes over will always be the same inside the interval – it’ll be that oneconst [active ...
that was declared at the rendering where thehandleButtonClick
was created.It looks like you want to queue up button values pressed when one is already active – consider pushing the future values to a stateful array, and use
useEffect
to move the first value in that array to theactive
state when needed. This way, you’ll never be depending on values in a possibly stale closure.The required functionality is probably called ‘debounce’ and can be easily implemented in React using the ‘useEffect’ hook:
setState (here setActive) is a async function hence updated value wont be print in console used just after it.
you can use
here prevState will have access to updated state
Here’s an alternative approach that uses promises instead of timeout. I think you will find that the complexity is reduced. Note we are careful to avoid
setState
calls on unmounted components. See the You Might Not Need An Effect guide from React –