Estoy creando un componente de fondo usando Vanta en NextJS, código a continuación:
import { useEffect, useRef, useState } from "react"; import * as THREE from "three"; import FOG from "vanta/dist/vanta.fog.min"; import { useDarkMode, useWindowSize } from "./Hooks"; const updateColor = (darkMode) => { return { highlightColor: darkMode ? 0xff0000 : 0xffd2c6, midtoneColor: darkMode ? 0xbe1d1d : 0xff7737, lowlightColor: darkMode ? 0x781212 : 0x69c3ff, baseColor: darkMode ? 0x0 : 0xffffff, } } export default function Background({ children }) { const [vantaEffect, setVantaEffect] = useState(); //returns the width and height of the window const windowSize = useWindowSize(); //user presses a button to change the theme from light to dark const [mode] = useDarkMode(); const vantaRef = useRef(); useEffect(() => { const isDark = mode === "dark"; if (vantaEffect) { setVantaEffect( vantaEffect.setOptions({ minHeight: windowSize.height, minWidth: windowSize.width, ...updateColor(isDark) })); vantaEffect.resize(); } else { setVantaEffect( FOG({ THREE, el: vantaRef.current, blurFactor: 0.18, minHeight: window.innerHeight, minWidth: window.innerWidth, ...updateColor(isDark) }) ) } return () => { if (vantaEffect) vantaEffect.destroy(); } }, [mode, windowSize]); return ( <div> <div className="fixed -z-50" ref={vantaRef}></div> <div>{children}</div> </div> ) }En este momento, si se actualiza el modo o el tamaño de la ventana, el lienzo cambiará de tamaño y se volverá a renderizar para el modo oscuro. Quiero poder detectar si estaba en modo oscuro o si la ventana que se está redimensionando ejecutó la función useEffect.
Además, cada vez que intento eliminar la función, me pide que agregue vantaEffect a las dependencias. Cuando lo hago, el efecto se renderiza demasiadas veces y retrasa la página.
¿Hay una mejor manera de usar ganchos para renderizar el fondo?
Quiero poder detectar si estaba en modo oscuro o si la ventana que se está redimensionando ejecutó la función useEffect.
Puede tener dos efectos en su componente, uno para el mode y el otro para el tamaño de la windowSize .
Además, cada vez que intento eliminar la función, me pide que agregue vantaEffect a las dependencias. Cuando lo hago, el efecto se renderiza demasiadas veces y retrasa la página.
Puede usar la actualización del estado funcional para acceder al estado anterior:
useEffect(() => { const isDark = mode === "dark"; setVantaEffect((previousVantaEffect) => { // use `previousVantaEffect` and return what you want }) }, [mode])Para dividir el mode y el cambio de tamaño de ventana, debe usar dos ganchos windowResize useEffect . Al dividirlos, estos ganchos solo se ejecutarán cuando se actualice la dependencia.
Lo que noté en su código es que ejecuta vantaEffect.destroy() en cada renderizado. Puedo estar equivocado, pero creo que eso no es lo que quieres. Si desea ejecutar este código solo al unmount , debe agregar otro useEffect sin dependencias en su matriz. (como se indica en los documentos de React:
¿Cuándo exactamente React limpia un efecto? React realiza la limpieza cuando el componente se desmonta. Sin embargo, como aprendimos anteriormente, los efectos se ejecutan para cada renderizado y no solo una vez. Es por eso que React también limpia los efectos del renderizado anterior antes de ejecutar los efectos la próxima vez.
https://reactjs.org/docs/hooks-effect.html#example-using-hooks-1 )
El total sería algo así:
useEffect(() => { const isDark = mode === "dark"; if (vantaEffect) { setVantaEffect( vantaEffect.setOptions({ ...updateColor(isDark) })); vantaEffect.resize(); } else { setVantaEffect( FOG({ THREE, el: vantaRef.current, blurFactor: 0.18, minHeight: window.innerHeight, minWidth: window.innerWidth, ...updateColor(isDark) }) ) } }, [mode]); useEffect(() => { if (vantaEffect) { setVantaEffect( vantaEffect.setOptions({ minHeight: windowSize.height, minWidth: windowSize.width })); vantaEffect.resize(); } else { setVantaEffect( FOG({ THREE, el: vantaRef.current, blurFactor: 0.18, minHeight: window.innerHeight, minWidth: window.innerWidth }) ) } }, [windowSize]); useEffect(() => { // only destroying the vantaEffect on unmount return () => vantaEffect?.destroy(); }, []);Deberías optimizar la salida, pero espero que entiendas la idea.