如何用useRef()实现React导航项active类切换(替代jQuery)
先看你原来的jQuery逻辑:点击#navbarSupportedContent下的li时,移除所有ul里li的active类,再给当前点击的li加上这个类。你用React的时候犯了几个典型错误——直接操作DOM不是React的核心思路,而且你的ref用法也有问题:同一个ref绑定多个li,最后只会指向最后一个元素,根本没法操作所有项。
正确的做法是用状态管理来控制激活状态,下面是完整的实现:
import { useState } from 'react'; function Navbar() { // 用状态存储当前激活的项标识,初始值设为"home"(对应Home项) const [activeTab, setActiveTab] = useState("home"); // 点击处理函数,接收当前项的唯一标识 const handleTabClick = (tabId) => { setActiveTab(tabId); }; return ( <div className="collapse navbar-collapse" id="navbarSupportedContent"> <ul className="navbar-nav ml-auto"> <div className="hori-selector"> <div className="left"></div> <div className="right"></div> </div> {/* 每个li根据activeTab动态判断是否添加active类 */} <li className={`nav-item ${activeTab === "dashboard" ? "active" : ""}`}> <a className="nav-link" href="javascript:void(0);" onClick={() => handleTabClick("dashboard")} > <i className="fas fa-tachometer-alt"></i> Dashboard </a> </li> <li className={`nav-item ${activeTab === "home" ? "active" : ""}`}> <a className="nav-link" href="javascript:void(0);" onClick={() => handleTabClick("home")} > <i className="fas fa-house-user"></i> Home </a> </li> <li className={`nav-item ${activeTab === "components" ? "active" : ""}`}> <a className="nav-link" href="javascript:void(0);" onClick={() => handleTabClick("components")} > <i className="far fa-clone"></i> Components </a> </li> <li className={`nav-item ${activeTab === "calendar" ? "active" : ""}`}> <a className="nav-link" href="javascript:void(0);" onClick={() => handleTabClick("calendar")} > <i className="far fa-calendar-alt"></i> Calendar </a> </li> </ul> </div> ); } export default Navbar;
关键说明:
- 用
useState创建activeTab状态,记录当前激活项的唯一标识(这里用字符串,你也可以用id或其他唯一值) - 每个li的
className通过模板字符串动态生成:如果当前项的标识和activeTab匹配,就加上active类,否则不加 - 给每个a标签绑定点击事件,点击时更新
activeTab的值,React会自动重新渲染页面,更新对应的类名
如果你非要用DOM操作(不推荐,违背React声明式编程的设计理念),也可以修正你的代码:
import { useRef, useEffect } from 'react'; function Navbar() { const tabsContainerRef = useRef(null); useEffect(() => { const container = tabsContainerRef.current; if (!container) return; const handleClick = (e) => { // 找到点击的li元素(如果点击的是a标签,就取其父元素) const targetLi = e.target.closest('li.nav-item'); if (!targetLi) return; // 移除所有li的active类 const allLis = container.querySelectorAll('li.nav-item'); allLis.forEach(li => li.classList.remove('active')); // 给当前点击的li加active类 targetLi.classList.add('active'); }; container.addEventListener('click', handleClick); // 组件卸载时清理事件监听 return () => container.removeEventListener('click', handleClick); }, []); return ( <div className="collapse navbar-collapse" id="navbarSupportedContent" ref={tabsContainerRef}> <ul className="navbar-nav ml-auto"> <div className="hori-selector"> <div className="left"></div> <div className="right"></div> </div> <li className="nav-item"> <a className="nav-link" href="javascript:void(0);"> <i className="fas fa-tachometer-alt"></i> Dashboard </a> </li> <li className="nav-item active"> <a className="nav-link" href="javascript:void(0);"> <i className="fas fa-house-user"></i> Home </a> </li> <li className="nav-item"> <a className="nav-link" href="javascript:void(0);"> <i className="far fa-clone"></i> Components </a> </li> <li className="nav-item"> <a className="nav-link" href="javascript:void(0);"> <i className="far fa-calendar-alt"></i> Calendar </a> </li> </ul> </div> ); } export default Navbar;
这个DOM操作版本用useEffect在组件挂载时添加事件监听,利用事件委托处理点击逻辑,但还是强烈建议用第一个状态管理的方案,更符合React的设计思想。
内容的提问来源于stack exchange,提问作者sp92
相关产品推荐
相关产品推荐

