¿Hay algún beneficio en el uso de useMemo (por ejemplo, para una llamada de función intensiva) en lugar de usar una combinación de useEffect y useState ?
Aquí hay dos ganchos personalizados que funcionan exactamente igual a primera vista, además de que el valor de retorno de useMemo es null en el primer renderizado:
import { expensiveCalculation } from "foo"; function useCalculate(someNumber: number): number { const [result, setResult] = useState<number>(null); useEffect(() => { setResult(expensiveCalculation(someNumber)); }, [someNumber]); return result; } import { expensiveCalculation } from "foo"; function useCalculateWithMemo(someNumber: number): number { return useMemo(() => { return expensiveCalculation(someNumber); }, [someNumber]); }; Ambos calculan el resultado cada vez que cambia su parámetro someNumber , ¿dónde se activa la memorización de useMemo ?
useEffect y setState generarán renderizaciones adicionales en cada cambio: la primera renderización se "retrasará" con datos obsoletos y luego pondrá inmediatamente en cola una renderización adicional con los nuevos datos.
Supongamos que tenemos:
// Maybe I'm running this on a literal potato function expensiveCalculation(x) { return x + 1; }; Supongamos que someNumber es inicialmente 0:
useMemo muestra inmediatamente 1 .useEffect renderiza null , luego, después de que el componente renderiza, el efecto se ejecuta, cambia el estado y pone en cola un nuevo renderizado con 1 . Entonces, si cambiamos someNumber a 2:
useMemo se ejecuta y se renderiza 3 .useEffect se ejecuta y representa 1 nuevamente, luego el efecto se activa y el componente se vuelve a ejecutar con el valor correcto de 3 . En términos de la frecuencia con la que se ejecuta el cálculo expensiveCalculation , los dos tienen un comportamiento idéntico, pero la versión useEffect está causando el doble de procesamiento, lo que es malo para el rendimiento por otras razones.
Además, la versión useMemo es simplemente más limpia y legible, en mi opinión. No introduce un estado mutable innecesario y tiene menos partes móviles.
Así que es mejor que useMemo aquí.
Creo que hay dos puntos principales que debe considerar al elegir entre ellos.
useEffect llamado después de que se haya renderizado el componente, para que pueda acceder a DOM desde él. Por ejemplo, esto es importante si desea acceder a elementos DOM a través de referencias.
useEffect garantiza que no se activará si las dependencias no han cambiado. useMemo no ofrece tales garantías.
Como se indica en la documentación de React , debe considerar useMemo como una técnica de optimización pura. Su programa debería continuar funcionando correctamente incluso si reemplaza useMemo con una llamada de función normal.
useEffect + useState se puede usar para controlar las actualizaciones. Incluso para romper dependencias circulares y evitar bucles de actualización infinitos.
Diría que además de la naturaleza asíncrona, podría haber alguna diferencia en términos de cómo están diseñados.
useEffect es una llamada colectiva, asíncrona o no, se recopila después de que se procesan todos los componentes.
useMemo es una llamada local, que solo tiene algo que ver con este componente. Podría pensar en useMemo como otra instrucción de asignación con beneficios para usar la asignación de la última actualización.
Esto significa que useMemo es más urgente, luego useLayoutEffect y el último useEffect .