导读:本期聚焦于小伙伴创作的《如何在 React 中为侧边栏不同菜单项实现点击切换图标与文字颜色》,敬请观看详情。侧边栏菜单点击后图标和文字颜色不变,是很多前端界面交互里的典型卡点。其本质在于组件未把当前选中项作为受控状态统一管理,导致样式无法随用户操作响应。常见错误是给每个菜单写独立 onClick 并直接改 DOM,这样在 React 的声明式渲染下极易失效。正确做法是用 useState 保存 activeKey,通过三元表达式切换 className 或内联样式,配合 CSS 变量统一控制颜色。图标可借字体图标或 SVG 组件按选中态传不同颜色值。这样不仅逻辑清晰,也方便后续扩展路由联动与权限隐藏。

在 React 应用里,侧边栏通常是页面布局的核心组成部分。当用户点击不同的菜单项时,希望对应的图标与文字颜色发生变化,从而明确当前所在模块,这是很基础也很实用的交互需求。实现这个功能的关键在于把“当前选中项”作为组件状态来管理,并基于该状态动态渲染样式。

如何在 React 中为侧边栏不同菜单项实现点击切换图标与文字颜色

为什么不能直接操作 DOM 修改颜色

一些初学者在 jQuery 时代习惯用点击事件直接找到节点改色,但在 React 中这种做法并不可取。React 的核心思想是声明式渲染,界面应该由状态(state)驱动。如果你在事件处理函数里用 document.querySelector 修改了某个菜单的颜色,当下一次组件因任何原因重新渲染时,React 会根据它自己维护的虚拟 DOM 覆盖掉你手动改的样式,导致颜色“闪一下又恢复”。

此外,直接操作 DOM 会让组件状态与界面表现不一致,后期维护时很难追踪某个菜单为什么是高亮态。当侧边栏需要支持路由跳转、权限控制或折叠展开时,这种写法会迅速失控。因此,我们应当放弃命令式思路,转向用状态控制类名或样式对象。

使用 useState 管理当前选中项

最直观的方案是在侧边栏组件里用 useState 保存一个标识当前选中菜单的 key。点击菜单时,调用 setActiveKey 更新状态,组件重新渲染,所有菜单根据 activeKey 判断自己是否选中,从而应用对应的颜色样式。

下面是一段简化但完整的示例代码,使用内联样式切换文字与图标颜色:

import React, { useState } from 'react';

// 模拟菜单数据
const menuList = [
  { key: 'home', label: '首页', icon: '🏠' },
  { key: 'user', label: '用户', icon: '👤' },
  { key: 'setting', label: '设置', icon: '⚙️' }
];

function Sidebar() {
  const [activeKey, setActiveKey] = useState('home');

  return (
    <div style={{ width: 200, padding: 10 }}>
      {menuList.map(item => {
        const isActive = item.key === activeKey;
        const color = isActive ? '#1890ff' : '#333';
        return (
          <div
            key={item.key}
            onClick={() => setActiveKey(item.key)}
            style={{
              cursor: 'pointer',
              padding: '8px 12px',
              color: color,
              fontSize: 14
            }}
          >
            <span style={{ marginRight: 8, color: color }}>{item.icon}</span>
            {item.label}
          </div>
        );
      })}
    </div>
  );
}

export default Sidebar;

上述代码中,activeKey 就是控制高亮的核心状态。每个菜单项的 color 变量根据 isActive 计算,图标和文字使用同一颜色值,保证了视觉一致。点击时只改状态,不碰 DOM,完全符合 React 设计理念。

结合 CSS 类名实现更灵活的样式

内联样式适合简单场景,但实际项目中通常用 CSS 文件定义选中态样式,便于统一主题。我们可以为菜单项动态添加 active 类名,在 CSS 中写清图标与文字颜色。

示例 CSS 与组件改造如下:

.menu-item {
  padding: 8px 12px;
  color: #333;
  cursor: pointer;
  font-size: 14px;
}
.menu-item.active {
  color: #1890ff;
}
.menu-item .icon {
  margin-right: 8px;
}
.menu-item.active .icon {
  color: #1890ff;
}
import React, { useState } from 'react';
import './sidebar.css';

const menuList = [
  { key: 'home', label: '首页', icon: '🏠' },
  { key: 'user', label: '用户', icon: '👤' },
  { key: 'setting', label: '设置', icon: '⚙️' }
];

function Sidebar() {
  const [activeKey, setActiveKey] = useState('home');

  return (
    <div className="sidebar">
      {menuList.map(item => (
        <div
          key={item.key}
          className={'menu-item' + (item.key === activeKey ? ' active' : '')}
          onClick={() => setActiveKey(item.key)}
        >
          <span className="icon">{item.icon}</span>
          {item.label}
        </div>
      ))}
    </div>
  );
}

export default Sidebar;

使用类名方案后,如果设计稿要求选中态文字加粗、图标放大,只需改 CSS,不必动 JS 逻辑。团队开发中,样式与行为分离也更利于协作。

使用 SVG 图标组件时的颜色控制

如果项目用的是 SVG 图标(如 Ant Design 的 @ant-design/icons),图标本身是组件,可通过 stylefill 属性接收颜色。下面演示传入当前颜色:

import React, { useState } from 'react';
import { HomeOutlined, UserOutlined, SettingOutlined } from '@ant-design/icons';

const menuList = [
  { key: 'home', label: '首页', Icon: HomeOutlined },
  { key: 'user', label: '用户', Icon: UserOutlined },
  { key: 'setting', label: '设置', Icon: SettingOutlined }
];

function Sidebar() {
  const [activeKey, setActiveKey] = useState('home');

  return (
    <div>
      {menuList.map(item => {
        const isActive = item.key === activeKey;
        const color = isActive ? '#1890ff' : '#333';
        const ItemIcon = item.Icon;
        return (
          <div
            key={item.key}
            onClick={() => setActiveKey(item.key)}
            style={{ color, cursor: 'pointer', padding: 8 }}
          >
            <ItemIcon style={{ color, marginRight: 8 }} />
            {item.label}
          </div>
        );
      })}
    </div>
  );
}

export default Sidebar;

这里把图标组件存进 Icon 属性,渲染时赋给 ItemIcon 并传 style。由于 Ant Design 图标默认使用 currentColor,父级 div 的 color 也会透传,所以即使不单独给图标设色也能生效。若需更精细控制,显式传 color 是最稳妥的。

与路由联动的进阶做法

当侧边栏需要配合 React Router 时,可以用 useLocation 读取当前路径作为 activeKey,而非仅用 useState。这样刷新页面或直链进入子页面,高亮依然正确。

import React from 'react';
import { useLocation, useNavigate } from 'react-router-dom';

const menuList = [
  { key: '/home', label: '首页' },
  { key: '/user', label: '用户' },
  { key: '/setting', label: '设置' }
];

function Sidebar() {
  const location = useLocation();
  const navigate = useNavigate();

  return (
    <div>
      {menuList.map(item => {
        const isActive = location.pathname === item.key;
        return (
          <div
            key={item.key}
            onClick={() => navigate(item.key)}
            style={{
              color: isActive ? '#1890ff' : '#333',
              cursor: 'pointer',
              padding: 8
            }}
          >
            {item.label}
          </div>
        );
      })}
    </div>
  );
}

export default Sidebar;

这种写法把选中态来源从内部状态变为路由地址,适合大多数后台系统。如果菜单 key 与路由不完全一致,可在数据里加 path 字段做映射。总之,无论哪种方式,核心都在于“单一数据源驱动视图”,避免手工改 DOM。

小结与避坑提醒

实现侧边栏菜单点击切换图标与文字颜色,本质是用状态记录选中项,并以该状态计算样式。新手常踩的坑包括:用 ref 或原生事件直接改色、在 map 里写死 index 当作 key、把图标当背景图无法继承颜色等。只要坚持声明式渲染,把交互转为状态更新,这类需求都能用几十行代码稳定解决。

如果后续侧边栏变复杂,比如要支持折叠、权限过滤、多层级,建议把菜单数据和选中逻辑抽成独立 hook,例如 useSidebar,保持组件干净。也可以引入 Context 让深层子菜单共享 activeKey,不必一层层传 props。

React侧边栏状态管理修改时间:2026-08-09 04:45:39

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。