繁体   English   中英

如何使用 React Hooks 更新不同的状态

[英]How to use React Hooks to update different states

我正在 NextJS 中使用Vanta制作背景组件,代码如下:

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>
    )
}

现在,如果更新了 mode 或 windowSize,canvas 将同时调整大小,并为暗模式重新渲染。 我希望能够检测它是暗模式还是正在调整大小的 window 运行 useEffect function。

此外,每当我尝试对 function 进行 lint 处理时,它都会要求我将vantaEffect 添加到依赖项中。 当我这样做时,效果会渲染太多次并滞后于页面。

有没有更好的方法来使用钩子来渲染背景?

我希望能够检测它是暗模式还是正在调整大小的 window 运行 useEffect function。

您可以在组件中使用两种效果,一种用于mode ,另一种用于windowSize

此外,每当我尝试对 function 进行 lint 处理时,它都会要求我将vantaEffect 添加到依赖项中。 当我这样做时,效果会渲染太多次并滞后于页面。

您可以使用功能 state 更新来访问以前的 state:

useEffect(() => {
    const isDark = mode === "dark";

    setVantaEffect((previousVantaEffect) => {
       // use `previousVantaEffect` and return what you want
    })

}, [mode])

要拆分modewindowResize ,您应该使用两个单独useEffect挂钩。 通过拆分它们,这些钩子将仅在更新依赖项时执行。

我在您的代码中注意到的是,您在每次渲染时都执行vantaEffect.destroy() 我可能弄错了,但我认为这不是你想要的。 如果您只想在unmount时执行此代码,您应该在其数组中添加另一个useEffect ,而不需要任何依赖项。 (如 React 文档中所述:

React 究竟何时清理效果? React 在组件卸载时执行清理。 然而,正如我们之前所了解的,效果会为每次渲染运行,而不仅仅是一次。 这就是为什么 React还会在下次运行效果之前清理上一次渲染中的效果。

https://reactjs.org/docs/hooks-effect.html#example-using-hooks-1

总数看起来像这样:

    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();
    }, []);

你应该优化 output,但我希望你明白

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM