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

React中动态加载元素如何实现同一时间仅单个添加active类

问题原因

当前实现存在两个核心问题导致多卡片同时处于选中态:

  • 每个VetItem组件独立维护自身的选中状态,组件之间没有状态同步逻辑
  • 直接通过原生DOM方法classList.toggle修改元素样式类,属于React反模式,UI渲染脱离了状态管控
修复方案

将选中状态上提到渲染所有医生卡片的父组件统一维护,仅存储当前选中的医生唯一ID,通过props将选中状态和点击回调下发给每个VetItem,保证同一时间最多只有一个卡片处于选中态。

1. 父组件改造

在遍历渲染所有医生卡片的父组件中,新增状态存储当前选中的医生ID:

// 医生列表父组件
import { useState, useEffect } from 'react';
import axios from 'axios';
import VetItem from './VetItem';

const DoctorList = () => {
  // 全局维护当前选中的医生ID,默认无选中
  const [selectedVetId, setSelectedVetId] = useState(null);
  const [vetList, setVetList] = useState([]);
  const userId = {
    activeUser: sessionStorage.getItem('activeUser')
  };

  // 把原来写在VetItem里的拉取医生列表逻辑移到父组件,避免每个卡片发重复请求
  useEffect(() => {
    axios
      .post('http://localhost:80/project-api/readActiveDoctor.php', userId)
      .then((res) => {
        setVetList(res.data);
      })
      .catch((err) => {
        console.log(err);
      });
  }, []);

  return (
    <div className="vet-list">
      {vetList.map((item) => (
        <VetItem
          key={item.id}
          uniqueId={item.id}
          name={item.name}
          surname={item.surname}
          specialization={item.specialization}
          age={item.age}
          gender={item.gender}
          email={item.email}
          contact={item.phoneNumber}
          doctorId={item.doctorId}
          room={item.room}
          // 下发选中状态和选中回调
          isSelected={selectedVetId === item.id}
          onSelect={() => setSelectedVetId(item.id)}
        />
      ))}
    </div>
  );
};

export default DoctorList;

如果需要支持点击已选中卡片取消选中,把onSelect回调替换为以下逻辑即可:

onSelect={() => setSelectedVetId(prev => prev === item.id ? null : item.id)}

2. VetItem组件改造

删除组件内部独立维护的选中状态、直接操作DOM的类名切换逻辑、重复的列表拉取逻辑,完全通过props驱动UI渲染:

const VetItem = (props) => {
  return (
    <div>
      <button
        onClick={props.onSelect}
        // 根据传入的选中状态判断是否加高亮类,完全由状态控制
        className={`individual-vet ${props.isSelected ? 'bg-salmon' : ''}`}
        id={props.uniqueId}
      >
        <div className='vet-block-img'>
          <img className='profileImg vet' src={dp} alt="医生头像" />
        </div>
        <div className='vet-block-text'>
          <h2>Dr. {props.name + ' ' + props.surname}</h2>
          <h4>{props.specialization}</h4>
        </div>
      </button>
    </div>
  );
};

export default VetItem;
优化说明
  • 修复后所有卡片的选中状态由父组件统一管控,同一时间只会有一个卡片匹配选中ID,从根源避免多卡片同时高亮的问题
  • 移除了直接操作DOM的反模式实现,遵循React状态驱动UI的设计原则
  • 把重复的医生列表接口请求移到父组件,避免N个卡片发送N次重复请求,减少性能浪费

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 19:18:21