如何在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')
相关代码
NavBar.js 文件代码
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';
问题原因及解决办法
报错原因
- DOM元素未加载完成:
useEffect空依赖数组会在组件挂载时立即执行,此时导航栏DOM可能还没渲染好,document.querySelector返回null,修改style自然报错。 - 选择器使用错误:
querySelector只接受一个选择器字符串,第二个参数会被忽略;且:hover是伪类选择器,无法通过该方法直接获取匹配元素。 - 违背React设计模式:React是状态驱动UI,直接操作DOM会破坏状态管理逻辑,容易出现UI和状态不一致的问题。
正确实现方式
用状态结合CSS类实现,完全符合React的设计思路:
- 修改组件逻辑,新增状态控制文本颜色切换:
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> ) }
- 在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
相关产品推荐
相关产品推荐

