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

React中如何正确处理多卡片的展开/收起className切换?

React多卡片展开的正确实现方式

直接通过e.target.classList.add("expandCard")操作DOM不是React推荐的最佳实践,原因有两点:

  1. React是状态驱动UI的框架,手动修改DOM会绕过状态管理,导致UI和内部状态不一致——比如组件重新渲染时,手动添加的class会被React的虚拟DOM diff覆盖。
  2. 多卡片场景下,点击卡片内的子元素(比如标题、文本段落)时,e.target可能不是外层的卡片div,这时候给子元素加class完全达不到预期效果。

正确的做法:用状态管理每个卡片的展开状态

多卡片场景下,只需要用一个对象或数组来记录每个卡片的展开状态即可,完全不存在无法用useState处理的问题。举个完整的示例:

import { useState } from 'react';

const CardList = () => {
  // 用对象存储展开状态,key是卡片唯一ID,value是布尔值(是否展开)
  const [expandedCards, setExpandedCards] = useState({});

  // 切换指定卡片的展开状态
  const toggleCardExpand = (cardId) => {
    setExpandedCards(prevState => ({
      ...prevState,
      [cardId]: !prevState[cardId] // 取反当前状态,实现展开/收起切换
    }));
  };

  // 模拟业务中的卡片数据(每个卡片要有唯一ID)
  const cards = [
    { id: 'card_01', title: '卡片1', content: '这是卡片1的完整内容,默认仅显示部分,点击展开全部' },
    { id: 'card_02', title: '卡片2', content: '这是卡片2的完整内容,默认仅显示部分,点击展开全部' },
    { id: 'card_03', title: '卡片3', content: '这是卡片3的完整内容,默认仅显示部分,点击展开全部' }
  ];

  return (
    <div className="card-container">
      {cards.map(card => (
        <div
          key={card.id}
          // 根据状态动态拼接class
          className={`card-item ${expandedCards[card.id] ? 'expandCard' : ''}`}
          // 点击时传入当前卡片ID,避免依赖e.target
          onClick={() => toggleCardExpand(card.id)}
        >
          <h4>{card.title}</h4>
          <p className="card-content">{card.content}</p>
        </div>
      ))}
    </div>
  );
};

export default CardList;

这个方案的优势

  • 完全遵循React的状态驱动模型,UI和状态始终保持一致,不会出现DOM和状态脱节的问题。
  • 逻辑清晰,容易扩展:比如要添加「全部收起」按钮,只需要把expandedCards重置为空对象即可。
  • 避免了e.target的不确定性,不管点击卡片内的哪个子元素,都会触发正确的卡片状态切换。

特殊场景下的DOM操作(不推荐)

如果确实因为某些复杂需求需要直接操作DOM,建议用React的useRef来获取DOM元素,而不是直接通过e.target:

import { useRef } from 'react';

const SingleCard = ({ cardData }) => {
  const cardRef = useRef(null);

  const handleClick = () => {
    cardRef.current.classList.toggle('expandCard');
  };

  return (
    <div ref={cardRef} className="card-item" onClick={handleClick}>
      <h4>{cardData.title}</h4>
      <p>{cardData.content}</p>
    </div>
  );
};

但还是要强调:这种方式仅适用于状态驱动无法覆盖的极端场景,大部分情况下优先选择状态管理的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 14:02:37