Reputation: 70466
I am playing around with React Hooks. When the button is clicked, I want to increment a counter. After the counter was incremented, the application should not allow further increments until clicked is reset to false.
I came up with this:
function App() {
const [counter, setCounter] = useState(0);
const [clicked, setClicked] = useState(false);
useEffect(() => {
if (clicked) {
setCounter(counter + 1);
setTimeout(() => {
setClicked(false);
}, 2000);
}
}, [clicked]);
return (
<div className="App">
<p>Clicked: {String(clicked)}</p>
<p>Counter: {counter}</p>
<button type="button" onClick={() => setClicked(true)}>
Click me
</button>
</div>
);
}
It actually works. However React is complaining with following warning:
React Hook useEffect has a missing dependency: 'counter'. Either include it or remove the dependency array. You can also do a functional update 'setCounter(c => ...)' if you only need 'counter' in the 'setCounter' call. (react-hooks/exhaustive-deps)
When I add the counter to the dependencies, useEffect will get into an infinite loop, because clicked is true and setCounter was called from within useEffect.
I want the counter only to be incremented, when clicked changed from false to true. That works if the dependency list only contains clicked, but React complains about that.
Try out for yourself: https://codesandbox.io/s/dreamy-shadow-7xesm
Upvotes: 3
Views: 4502
Reputation: 480
Your problem with infinite loop will be gone if you remove the timeout. (btw what is it for? Are you trying to implement a debounce or throttle?)
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [counter, setCounter] = useState(0);
const [clicked, setClicked] = useState(false);
useEffect(() => {
if (clicked) {
setClicked(false);
setCounter(counter + 1);
}
}, [clicked, counter]);
return (
<div className="App">
<p>Clicked: {String(clicked)}</p>
<p>Counter: {counter}</p>
<button type="button" onClick={() => setClicked(true)}>
Click me
</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Upvotes: 1
Reputation: 3377
Try replacing setCounter(counter + 1) with this:
setCounter(counter => counter + 1)
Like the warning says. Should solve it.
Upvotes: 12