I have a component that looks like this (very simplified version):
const component = (props: PropTypes) => {
const [allResultsVisible, setAllResultsVisible] = useState(false);
const renderResults = () => {
return (
<section>
<p onClick={ setAllResultsVisible(!allResultsVisible) }>
More results v
</p>
{
allResultsVisible &&
<section className="entity-block--hidden-results">
...
</section>
}
</section>
);
};
return <div>{ renderResults() }</div>;
}
When I load the page this component is used on, I get this error: Uncaught Invariant Violation: Rendered more hooks than during the previous render.
I tried to find an explanation of this error, but my searching returned no results.
When I modify the component slightly:
const component = (props: PropTypes) => {
const [allResultsVisible, setAllResultsVisible] = useState(false);
const handleToggle = () => {
setAllResultsVisible(!allResultsVisible);
}
const renderResults = () => {
return (
<section>
<p onClick={ handleToggle }>
More results v
</p>
{
allResultsVisible &&
<section className="entity-block--hidden-results">
...
</section>
}
</section>
);
};
return <div>{ renderResults() }</div>;
}
I no longer get that error. Is it because I included the setState
function within the jsx that is returned by renderResults
? It would be great to have an explanation of why the fix works.
The fix works because the first code sample (the erroring one) invokes a function inside onClick
, while the second (the working one) passes a function to onClick
. The difference is those all-important parentheses, which in JavaScript mean 'invoke this code'.
Think of it this way: in the first code sample, every time component
is rendered, renderResults
is invoked. Every time that happens, setAllResultsVisible(!allResultsVisible)
, rather than waiting for a click, is called. Since React performs the render on its own schedule, there's no telling how many times that will happen.
From the React docs:
With JSX you pass a function as the event handler, rather than a string.
Note: I wasn't able to get this exact error message when running the first code sample in a sandbox. My error referred to an infinite loop. Maybe a more recent version of React produces the error described?