Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
50
rated 0 times [  51] [ 1]  / answers: 1 / hits: 194847  / 5 Years ago, wed, april 10, 2019, 12:00:00

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.


More From » reactjs

 Answers
30

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.




React Handling Events Docs



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?


[#52260] Monday, April 8, 2019, 5 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
kaceyr

Total Points: 510
Total Questions: 97
Total Answers: 116

Location: Solomon Islands
Member since Fri, Oct 8, 2021
3 Years ago
kaceyr questions
;