You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React项目系统主题变更时Landing与Navbar组件图片不切换问题

问题描述

我开发的React网站已实现深色主题切换及系统主题检测功能,但存在以下问题:

  • 当修改系统主题时,Landing和Navbar组件的图片无法同步切换;
  • 通过themeChange()函数手动切换主题时,这两个组件的图片能正常切换,且网站其他元素均可随系统主题变更正常切换。

Home.jsx 代码

function Home() {
    const [darkTheme, setDarkTheme] = useState()
    const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)').matches;

    useEffect(() => {
        if(prefersDarkScheme) {
            document.body.classList.toggle("light-theme");
            setDarkTheme(prefersDarkScheme)
        } else {
            document.body.classList.toggle("dark-theme");
            setDarkTheme(prefersDarkScheme)
        }
    }, [])

    function themeChange() {
        if(prefersDarkScheme) {
            document.body.classList.toggle("light-theme");
            setDarkTheme(!darkTheme)
        } else {
            document.body.classList.toggle("dark-theme");
            setDarkTheme(!darkTheme)
        }
    };

    return(
        <div className="Home fade" id="home">
            <Navbar themeChange={themeChange} darkTheme={darkTheme} />
            <Landing darkTheme={darkTheme} />
            <About />
            <Skills />
            <Projects />
            <Contact />
            <Footer />
        </div>
    )
}

Landing组件代码(Navbar逻辑一致)

function Landing(props) {
  const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)').matches;
  const [darkNav, setDarkNav] = useState(props.darkTheme)
  useEffect(() => {
    if(props.darkTheme === true){
        setDarkNav(true)
    } else if (props.darkTheme === false) {
        setDarkNav(false)
    } else {
        setDarkNav(prefersDarkScheme)
    }
}, [props.darkTheme])

    return(
        <div className='Landing-Page'>
            <div className='Landing-box'>
                <div className='Landing-Text'>
                    <h1>Bridger Brown</h1>
                    <h2>Front-End Web Developer + Designer</h2>
                </div>
                <div className='landpages'>
                    {
                        !darkLand ?
                        <img src='./src/assets/wave-dark.jpg' className="fade" id='land-bg'/>
                        :
                        <img src='./src/assets/wave-light.jpg' className="fade" id='land-bg2'/>
                    }

                </div>
            </div>
        </div>
    )
} 
问题原因与修复方案

问题原因

  1. Home组件未监听系统主题变化:prefersDarkScheme仅在组件初始化时获取一次值,当系统主题后续变更时,不会触发darkTheme状态更新,导致子组件Landing/Navbar接收的darkThemeprops没有变化,图片切换逻辑无法触发。
  2. Landing组件变量名错误:JSX中判断用的是darkLand,但组件内定义的状态是darkNav,这会导致图片切换逻辑完全失效(即使props更新)。

修复步骤

1. 给Home组件添加系统主题监听

修改Home组件的useEffect,监听媒体查询的change事件,实时更新主题状态:

function Home() {
    const [darkTheme, setDarkTheme] = useState()
    // 获取媒体查询对象
    const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)');

    useEffect(() => {
        // 初始化主题
        const updateTheme = (e) => {
            const isDark = e.matches;
            setDarkTheme(isDark);
            // 更新body类名
            document.body.classList.toggle("dark-theme", isDark);
            document.body.classList.toggle("light-theme", !isDark);
        };
        // 初始化执行一次
        updateTheme(darkModeQuery);
        // 添加监听事件
        darkModeQuery.addEventListener('change', updateTheme);
        // 清理函数
        return () => darkModeQuery.removeEventListener('change', updateTheme);
    }, [])

    function themeChange() {
        // 手动切换时反转状态
        const newDarkTheme = !darkTheme;
        setDarkTheme(newDarkTheme);
        document.body.classList.toggle("dark-theme", newDarkTheme);
        document.body.classList.toggle("light-theme", !newDarkTheme);
    };

    return(
        <div className="Home fade" id="home">
            <Navbar themeChange={themeChange} darkTheme={darkTheme} />
            <Landing darkTheme={darkTheme} />
            <About />
            <Skills />
            <Projects />
            <Contact />
            <Footer />
        </div>
    )
}

2. 修复Landing组件的变量名错误

将JSX中的darkLand替换为darkNav,同时简化状态更新逻辑:

function Landing(props) {
  // 无需重复定义媒体查询,直接使用props传递的darkTheme即可
  const [darkNav, setDarkNav] = useState(props.darkTheme)
  
  useEffect(() => {
    setDarkNav(props.darkTheme);
  }, [props.darkTheme])

    return(
        <div className='Landing-Page'>
            <div className='Landing-box'>
                <div className='Landing-Text'>
                    <h1>Bridger Brown</h1>
                    <h2>Front-End Web Developer + Designer</h2>
                </div>
                <div className='landpages'>
                    {
                        !darkNav ?
                        <img src='./src/assets/wave-dark.jpg' className="fade" id='land-bg'/>
                        :
                        <img src='./src/assets/wave-light.jpg' className="fade" id='land-bg2'/>
                    }
                </div>
            </div>
        </div>
    )
} 

3. 优化说明

  • 统一用document.body.classList.toggle(className, condition)的方式切换类名,逻辑更清晰,避免重复判断。
  • 移除Landing组件中冗余的媒体查询,直接依赖父组件传递的darkThemeprops,保持数据流向一致。
  • 添加监听事件的清理函数,避免内存泄漏。

内容的提问来源于stack exchange,提问作者ILLUSORY

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 00:25:31