Tengo un componente que se ve así (versión muy simplificada):
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>; } Cuando cargo la página en la que se usa este componente, aparece este error: Uncaught Invariant Violation: Rendered more hooks than during the previous render. Traté de encontrar una explicación de este error, pero mi búsqueda no arrojó resultados.
Cuando modifico el componente ligeramente:
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>; } Ya no me sale ese error. ¿Es porque incluí la función setState dentro del jsx que devuelve renderResults ? Sería genial tener una explicación de por qué funciona la corrección.
La solución funciona porque la primera muestra de código (la que da error) invoca una función dentro de onClick , mientras que la segunda (la que funciona) pasa una función a onClick . La diferencia son esos paréntesis tan importantes, que en JavaScript significan 'invocar este código'.
Piénselo de esta manera: en la primera muestra de código, cada vez que se procesa el component , se invoca renderResults . Cada vez que eso sucede, setAllResultsVisible(!allResultsVisible) , en lugar de esperar un clic. Dado que React realiza el renderizado en su propio horario, no se sabe cuántas veces sucederá.
De los documentos de React:
Con JSX, pasa una función como controlador de eventos, en lugar de una cadena.
Documentos de eventos de manejo de React
Nota: No pude recibir este mensaje de error exacto cuando ejecuté el primer ejemplo de código en un espacio aislado. Mi error se refería a un bucle infinito. ¿Quizás una versión más reciente de React produce el error descrito?
Me enfrenté al mismo problema. Lo que estaba haciendo era algo como esto:
const Table = (listings) => { const {isLoading} = useSelector(state => state.tableReducer); if(isLoading){ return <h1>Loading...</h1> } useEffect(() => { console.log("Run something") }, []) return (<table>{listings}</table>) }Creo que lo que sucedió fue que en el primer renderizado, el componente regresó temprano y useEffect no se ejecutó. Cuando el estado de isLoading cambió, useEffect se ejecutó y obtuve el error: el enlace se procesó más veces que el procesamiento anterior.
Un simple cambio lo arregló:
const Table = (listings) => { const {isLoading} = useSelector(state => state.tableReducer); useEffect(() => { console.log("Run something") }, []) if(isLoading){ return <h1>Loading...</h1> } return (<table>{listings}</table>) }Simplemente puede cambiar su evento onlick agregar () => antes de setAllResultsVisible
<p onClick={() => setAllResultsVisible(!allResultsVisible) }> More results v </p>y funcionará perfectamente