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

如何在React的useEffect中实现滚动导航文字变色?解决空值报错

问题:滚动时修改导航文本颜色报错 Cannot read properties of null (reading 'style')

需求是屏幕向上滚动时,将导航栏内的About、Experience、Projects、Connect文本设置为黄色。尝试在React组件的useEffect钩子中通过DOM操作修改样式,但运行时报错:

Cannot read properties of null (reading 'style') TypeError: Cannot read properties of null (reading 'style')


相关代码

import { useState, useEffect } from "react";
import { Navbar, Nav, Container } from "react-bootstrap";
import navIcon1 from '../assets/img/nav-icon1.svg';
import navIcon3 from '../assets/img/nav-icon3.svg';
import { HashLink } from 'react-router-hash-link';
import { BrowserRouter as Router } from "react-router-dom";

export const NavBar = () => {

  const [activeLink, setActiveLink] = useState('home');
  const [scrolled, setScrolled] = useState(false);

  useEffect(() => {
    const box = document.querySelector('nav.navbar .navbar-nav a.nav-link.navbar-link:hover', 'nav.navbar .navbar-nav a.nav-link.navbar-link.active');
    box.style.color = '#64ffda !important';
    const onScroll = () => {
      if (window.scrollY > 50) {
        setScrolled(true);
      } else {
        box.style.color = '#64ffda !important';
        setScrolled(false);
      }
    }

    window.addEventListener("scroll", onScroll);

    return () => window.removeEventListener("scroll", onScroll);
  }, [])

  const onUpdateActiveLink = (value) => {
    setActiveLink(value);
  }

  return (
    <Router>
      <Navbar expand="md" className={scrolled ? "scrolled" : ""}>
        <Container>
          <Navbar.Toggle aria-controls="basic-navbar-nav">
            <span className="navbar-toggler-icon"></span>
          </Navbar.Toggle>
          <Navbar.Collapse id="basic-navbar-nav">
            <Nav className="ms-auto">
              <Nav.Link href="#about" className={activeLink === 'about' ? 'active navbar-link' : 'navbar-link'} onClick={() => onUpdateActiveLink('abouts')}>About</Nav.Link>
              <Nav.Link href="#experience" className={activeLink === 'experience' ? 'active navbar-link' : 'navbar-link'} onClick={() => onUpdateActiveLink('experiences')}>Experience</Nav.Link>
              <Nav.Link href="#project" className={activeLink === 'project' ? 'active navbar-link' : 'navbar-link'} onClick={() => onUpdateActiveLink('projects')}>Projects</Nav.Link>
              <Nav.Link href="#connect" className={activeLink === 'connect' ? 'active navbar-link' : 'navbar-link'} onClick={() => onUpdateActiveLink('connect')}>Connect</Nav.Link>
            </Nav>
            <span className="navbar-text">
              <div className="social-icon">
                <a href="#" target="_blank"><img src={navIcon1} alt="" /></a>
                <a href="#" target="_blank"><img src={navIcon3} alt="" /></a>
              </div>
              <HashLink to=''>
                <button className="vvd"><span>Resume</span></button>
              </HashLink>
            </span>
          </Navbar.Collapse>
        </Container>
      </Navbar>
    </Router>
  )
}

CSS 文件代码

nav.navbar .navbar-nav a.nav-link.navbar-link:hover,
nav.navbar .navbar-nav a.nav-link.navbar-link.active {
  opacity: 1;
  color: #64ffda !important;
}

尝试添加到useEffect中的代码

const box = document.querySelector('nav.navbar .navbar-nav a.nav-link.navbar-link:hover', 'nav.navbar .navbar-nav a.nav-link. navbar-link.active');
box.style.color = '#64ffda !important';

问题原因及解决办法

报错原因

  1. DOM元素未加载完成:useEffect空依赖数组会在组件挂载时立即执行,此时导航栏DOM可能还没渲染好,document.querySelector返回null,修改style自然报错。
  2. 选择器使用错误:querySelector只接受一个选择器字符串,第二个参数会被忽略;且:hover是伪类选择器,无法通过该方法直接获取匹配元素。
  3. 违背React设计模式:React是状态驱动UI,直接操作DOM会破坏状态管理逻辑,容易出现UI和状态不一致的问题。

正确实现方式

用状态结合CSS类实现,完全符合React的设计思路:

  1. 修改组件逻辑,新增状态控制文本颜色切换:
import { useState, useEffect } from "react";
// 其他导入保持不变

export const NavBar = () => {
  const [activeLink, setActiveLink] = useState('home');
  const [scrolled, setScrolled] = useState(false);
  // 新增状态:控制导航文本是否为黄色
  const [navTextYellow, setNavTextYellow] = useState(false);

  useEffect(() => {
    const onScroll = () => {
      const isScrolled = window.scrollY > 50;
      setScrolled(isScrolled);
      // 滚动超过50px时切换为黄色,否则恢复原颜色
      setNavTextYellow(isScrolled);
    }

    window.addEventListener("scroll", onScroll);
    return () => window.removeEventListener("scroll", onScroll);
  }, [])

  const onUpdateActiveLink = (value) => {
    setActiveLink(value);
  }

  return (
    <Router>
      <Navbar expand="md" className={scrolled ? "scrolled" : ""}>
        <Container>
          <Navbar.Toggle aria-controls="basic-navbar-nav">
            <span className="navbar-toggler-icon"></span>
          </Navbar.Toggle>
          <Navbar.Collapse id="basic-navbar-nav">
            <Nav className="ms-auto">
              {/* 给每个导航项添加动态类 */}
              <Nav.Link 
                href="#about" 
                className={`${activeLink === 'about' ? 'active navbar-link' : 'navbar-link'} ${navTextYellow ? 'nav-yellow' : ''}`} 
                onClick={() => onUpdateActiveLink('about')}
              >About</Nav.Link>
              <Nav.Link 
                href="#experience" 
                className={`${activeLink === 'experience' ? 'active navbar-link' : 'navbar-link'} ${navTextYellow ? 'nav-yellow' : ''}`} 
                onClick={() => onUpdateActiveLink('experience')}
              >Experience</Nav.Link>
              <Nav.Link 
                href="#project" 
                className={`${activeLink === 'project' ? 'active navbar-link' : 'navbar-link'} ${navTextYellow ? 'nav-yellow' : ''}`} 
                onClick={() => onUpdateActiveLink('project')}
              >Projects</Nav.Link>
              <Nav.Link 
                href="#connect" 
                className={`${activeLink === 'connect' ? 'active navbar-link' : 'navbar-link'} ${navTextYellow ? 'nav-yellow' : ''}`} 
                onClick={() => onUpdateActiveLink('connect')}
              >Connect</Nav.Link>
            </Nav>
            <span className="navbar-text">
              <div className="social-icon">
                <a href="#" target="_blank"><img src={navIcon1} alt="" /></a>
                <a href="#" target="_blank"><img src={navIcon3} alt="" /></a>
              </div>
              <HashLink to=''>
                <button className="vvd"><span>Resume</span></button>
              </HashLink>
            </span>
          </Navbar.Collapse>
        </Container>
      </Navbar>
    </Router>
  )
}
  1. 在CSS中添加nav-yellow类的样式:
/* 滚动时的黄色文本样式 */
nav.navbar .navbar-nav a.nav-link.navbar-link.nav-yellow {
  color: yellow !important;
}

/* 保留原有hover和激活状态样式 */
nav.navbar .navbar-nav a.nav-link.navbar-link:hover,
nav.navbar .navbar-nav a.nav-link.navbar-link.active {
  opacity: 1;
  color: #64ffda !important;
}

额外优化点

原代码中onUpdateActiveLink存在拼写错误:比如点击About时设置activeLink为'abouts',但判断激活状态的条件是activeLink === 'about',会导致激活样式不生效,已在上述代码中修正。


内容的提问来源于stack exchange,提问作者Muhammad Bahruddin Saputra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 05:12:05