Uncaught Invariant Violation: Rendered more hooks than during the previous render
Solution 1:
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?
Solution 2:
I faced the same issue. What I was doing was something like this:
const Table = (listings) => {
const {isLoading} = useSelector(state => state.tableReducer);
if(isLoading){
return <h1>Loading...</h1>
}
useEffect(() => {
console.log("Run something")
}, [])
return (<table>{listings}</table>)
}
I think what was happening was that on the first render, the component returned early and the useEffect didn't run. When the isLoading state changed, the useEffect ran and I got the error - the hook rendered more times than the previous render.
A simple change fixed it:
const Table = (listings) => {
const {isLoading} = useSelector(state => state.tableReducer);
useEffect(() => {
console.log("Run something")
}, [])
if(isLoading){
return <h1>Loading...</h1>
}
return (<table>{listings}</table>)
}
Solution 3:
You can simply change your onlick event add () =>
before setAllResultsVisible
<p onClick={() => setAllResultsVisible(!allResultsVisible) }>
More results v
</p>
and it will work perfectly