Con los nuevos ganchos de efectos de React, puedo decirle a React que omita la aplicación de un efecto si ciertos valores no han cambiado entre renderizaciones. Ejemplo de los documentos de React:
useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); // Only re-run the effect if count changes
Pero el ejemplo anterior aplica el efecto sobre el procesamiento inicial y sobre los re-procesamientos subsiguientes donde el count
ha cambiado. ¿Cómo puedo decirle a React que omita el efecto en el renderizado inicial?
Como dice la guía,
Effect Hook, useEffect, agrega la capacidad de realizar efectos secundarios desde un componente de función. Tiene el mismo propósito que el componenteDidMount, el componenteDidUpdate y el componenteWillUnmount en las clases de React, pero unificado en una sola API.
En este ejemplo de la guía, se espera que el count
sea 0 solo en el renderizado inicial:
const [count, setCount] = useState(0);
Entonces funcionará como componentDidUpdate
con verificación adicional:
useEffect(() => { if (count) document.title = `You clicked ${count} times`; }, [count]);
Básicamente, así es como puede funcionar el gancho personalizado que se puede usar en lugar de useEffect
:
function useDidUpdateEffect(fn, inputs) { const didMountRef = useRef(false); useEffect(() => { if (didMountRef.current) { return fn(); } didMountRef.current = true; }, inputs); }
Los créditos van a @Tholle por sugerir useRef
en lugar de setState
.
Aquí hay un enlace personalizado que solo proporciona un indicador booleano para indicar si el renderizado actual es el primero (cuando se montó el componente). Es casi lo mismo que algunas de las otras respuestas, pero puede usar el indicador en un useEffect
o la función de procesamiento o en cualquier otro lugar del componente que desee. Tal vez alguien pueda proponer un nombre mejor.
import { useRef, useEffect } from 'react'; export const useIsMount = () => { const isMountRef = useRef(true); useEffect(() => { isMountRef.current = false; }, []); return isMountRef.current; };
Puedes usarlo como:
import React, { useEffect } from 'react'; import { useIsMount } from './useIsMount'; const MyComponent = () => { const isMount = useIsMount(); useEffect(() => { if (isMount) { console.log('First Render'); } else { console.log('Subsequent Render'); } }); return isMount ? <p>First Render</p> : <p>Subsequent Render</p>; };
Y aquí hay una prueba para ello si estás interesado:
import { renderHook } from '@testing-library/react-hooks'; import { useIsMount } from '../useIsMount'; describe('useIsMount', () => { it('should be true on first render and false after', () => { const { result, rerender } = renderHook(() => useIsMount()); expect(result.current).toEqual(true); rerender(); expect(result.current).toEqual(false); rerender(); expect(result.current).toEqual(false); }); });
Nuestro caso de uso fue ocultar elementos animados si los accesorios iniciales indican que deben ocultarse. En renderizaciones posteriores, si los accesorios cambiaron, queríamos que los elementos se animaran.
Encontré una solución que es más simple y no necesita usar otro gancho, pero tiene inconvenientes.
useEffect(() => { // skip initial render return () => { // do something with dependency } }, [dependency])
Esto es solo un ejemplo de que hay otras formas de hacerlo si tu caso es muy sencillo.
El inconveniente de hacer esto es que no puede tener un efecto de limpieza y solo se ejecutará cuando la matriz de dependencia cambie por segunda vez.
No se recomienda usar esto y debe usar lo que dicen las otras respuestas, pero solo agregué esto aquí para que las personas sepan que hay más de una forma de hacerlo.
Solo para que quede más claro, no debe usar este enfoque para resolver el problema en la pregunta (omitiendo el renderizado inicial), esto es solo para fines didácticos que muestran que puede hacer lo mismo de diferentes maneras. Si necesita omitir el procesamiento inicial, utilice el enfoque en otras respuestas.