I have an accordion item and I am trying to only fire the method doSomething
the first time the item is open:
const AccordionItem = ({index, a, b, c}: Props) => {
const [isOpen, setIsOpen] = useState(false);
const [counter, setCounter] = useState(0);
if (isOpen) {
setCounter(counter + 1);
}
if (counter === 1) {
doSomething();
}
return (
<Accordion>
<Title onClick={() => setIsOpen(!isOpen)}>
...
</Accordion>
);
}
When I click the title, doSomething
fires twice and I get an error: Uncaught Invariant Violation: Too many re-renders
.
Why is it re-rendering like crazy?
How does doSomething
fire twice if the condition is counter === 1
?
I tried using useEffect
to fire the event once but that didn't make sense as it fired on componentDidMount
which wasn't triggered by the first click.
I would like to understand what is going on with useState, my logic and any pointers on how I can debug the re-renders.
Why is it re-rendering like crazy?
I think that is because you are changing the state in the render function so that trigger a side-effect.
I tried using useEffect to fire the event once but that didn't make sense as it fired on componentDidMount which wasn't triggered by the first click.
useEffect its also componentDidUpdate event
And you can handle the event in an auxiliary function "toggle"
function App() {
const [isOpen, setIsOpen] = useState(false);
const [counter, setCounter] = useState(0);
function toggle() {
if (!isOpen) {
setCounter(counter + 1);
}
setIsOpen(!isOpen);
}
useEffect(() => {
if (counter === 1) {
doSomething();
}
}, [counter]);
return (
<div className="App">
<button onClick={() => toggle()}>Click here</button>
</div>
);
}
The "[counter]" says that whenever the counter variable change, the callback function is going to be executed.
useEffect(() => {
if (counter === 1) {
doSomething();
}
}, [counter]);