Uncaught invariant violation: Rendered with more hooks than previous render
P粉477369269
P粉477369269 2024-03-25 16:50:53
0
2
565

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 a page that uses this component, I get this error: Uncaught Invariant Violation: Rendered more hooks than during the previous render. I tried to find an explanation for this error, but my search returned no results result.

When I slightly modify the component:

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 receive this error. Is it because I included the setState function in the jsx returned by renderResults? It would be great if there was an explanation as to why this fix works.

P粉477369269
P粉477369269

reply all(2)
P粉729198207

I also encountered the same problem. What I'm doing is 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>)
}

What I think is happening is that on the first render, the component returns early and useEffect doesn't run. When the isLoading state changes and useEffect runs, I get the error - The hook renders more times than it did before.

A simple change solved the problem:

const Table = (listings) => {
    
    const {isLoading} = useSelector(state => state.tableReducer);
        
    useEffect(() => {
        console.log("Run something")
    }, [])
    
    if(isLoading){
        return <h1>Loading...</h1>
    }
    return (<table>{listings}</table>)
}
P粉448346289

The fix works because the first code example (the wrong code) calls a function inside onClick, while the second code example (the working code example) passes the function Gave onClick. The difference is those all-important parentheses, which in JavaScript mean "call this code".

Think of it this way: In the first code example, renderResults is called every time a component is rendered. Each time this happens, setAllResultsVisible(!allResultsVisible) is called instead of waiting for the click. Since React performs rendering on its own schedule, there's no way to determine how many times this will occur.

From React documentation:

React processing event document

Note: I can't get the exact error message when running the first code example in the sandbox. My error involves an infinite loop. Maybe a newer version of React produces the error described?

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template