Estaba haciendo algunas pruebas con el siguiente componente ficticio, donde tras la ejecución (en la consola) obtengo el siguiente resultado:
Rendering: 0 Triggered: 0 Rendering: 4 Triggered: 4 Rendering: 4Lucho por entender por qué.
Primera representación:
index en 0 .undefined no es 0index en 4Segundo render:
index es 4Tercer renderizado:
Lo que esperaría es:
Rendering: 0 Triggered: 0 Rendering: 4¿Me estoy saltando algo muy obvio? ¿Podría por favor ayudarme a entender cómo funciona esto debajo del capó?
const Example = React.memo(() => { const [index, setIndex] = React.useState(0) console.log('Rendering: ', index) React.useEffect(() => { console.log('Triggered: ', index) setIndex(4) }, [index]) return <h1>{index}</h1> }) ReactDOM.render(<Example />, document.body); <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>El número de renderizados es realmente correcto. Analicemos lo que sucede:
useEffect de uso se ejecuta automáticamente)useEffectindex en 4index de 0 a 44 a 4 (incluso el valor es el mismo, activará la representación del componente porque React no sabe si estableció el mismo estado y debe ejecutarse nuevamente). En esta representación , useEffect no se ejecuta porque index es 4 nuevamente. Si algo cambia en un componente en cualquier momento, como useState useContext , customHook , ese componente deberá volver a procesarse. Esto también sucede si el componente principal se vuelve a renderizar, el componente secundario se volverá a renderizar incluso si su componente no tuvo ningún cambio.
Para evitar que ocurra una reproducción innecesaria de los componentes secundarios, puede usar React.memo , esto volverá a procesar su componente si los accesorios cambian, pero no evitará que su componente se vuelva a procesar si el estado o cualquiera de los ganchos anteriores cambian allí.
Si esto parece redundante, lo parece, pero es necesario para que react esté seguro de que tiene el último estado. Ejecutar JS de esta manera es más rápido que tener una memoria de estado que verifique los cambios y también es más transparente para el desarrollador (y cómo se crea el VDOM )
No se puede lograr el resultado esperado.
useEffect se procesa cuando se monta el componente y cada vez que se vuelve a procesar cuando cambia el estado (índice).
const Example = () => { const [index, setIndex] = React.useState(0) console.log('Rendering: ', index) React.useEffect(() => { console.log('Triggered: ', index) setIndex(4) }, [index]) return <h1>{index}</h1> }Producción:
La forma en que funciona useEffect es que solo se ejecuta después de que se procesa el componente de la página.
Espero que esto te ayude a entender.
El primer índice de renderizado es 0.
Rendering: 0Activa el useEffect.
Triggered: 0El índice se actualiza en useEffect pero no en el componente. Luego render actualiza el índice a 4.
Rendering: 4useEffect se ejecuta porque el índice ha cambiado.
Triggered: 4El componente se vuelve a representar pero el índice sigue siendo 4, por lo que useEffect no se ejecutará nuevamente.
Rendering: 4