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

React map循环中点击单个项切换开合全列表生效的解决方法

问题原因

你当前所有列表项共用同一个open布尔状态,只要修改这个状态,所有绑定了该状态的列表项都会同步响应,自然会出现点击任意项全部同步变更的问题。

解决方案

根据你的业务需求可以选择以下两种实现方案:


方案1:允许同时展开多个列表项

将state改为存储键值对对象,键为列表项的唯一标识,值为对应项的开合状态:

import React, { useState } from 'react';

// 初始化state为空对象,默认所有项都是关闭状态
const [openMap, setOpenMap] = useState({});

{
  FilterAvailable.map((item, index) => {
    // 优先用item自身的业务唯一id作为标识,没有的话可临时用index
    const itemKey = item.id ?? index;
    // 读取当前项的开合状态,默认false关闭
    const isOpen = openMap[itemKey] ?? false;
    return (
      <li className="filterItem" key={itemKey}>
        <div
          className="filterBtn flex align-center justify-between"
          onClick={() => {
            setOpenMap(prev => ({
              ...prev,
              // 仅修改当前点击项的状态
              [itemKey]: !isOpen
            }))
          }}
        >
          <h2>{item.catogery}</h2>
          <div>
            {isOpen ? (
              <IoIosArrowDown className="downArrow" />
            ) : (
              <IoIosArrowUp className="downArrow" />
            )}
          </div>
        </div>

        {item.options.map(option => {
          return (
            <React.Fragment key={option}>
              {isOpen && (
                <ul className="filterOption">
                  <li className="filterOptionitem">
                    <button>{option}</button>
                  </li>
                </ul>
              )}
            </React.Fragment>
          );
        })}
      </li>
    );
  });
}

方案2:同一时间仅允许展开一个列表项(互斥展开)

将state改为存储当前展开项的唯一标识,默认设为null代表所有项都关闭:

import React, { useState } from 'react';

// 初始化无展开项
const [activeOpenId, setActiveOpenId] = useState(null);

{
  FilterAvailable.map((item, index) => {
    const itemKey = item.id ?? index;
    const isOpen = activeOpenId === itemKey;
    return (
      <li className="filterItem" key={itemKey}>
        <div
          className="filterBtn flex align-center justify-between"
          onClick={() => {
            // 点击已展开的项则关闭,否则切换为当前点击项展开
            setActiveOpenId(isOpen ? null : itemKey)
          }}
        >
          <h2>{item.catogery}</h2>
          <div>
            {isOpen ? (
              <IoIosArrowDown className="downArrow" />
            ) : (
              <IoIosArrowUp className="downArrow" />
            )}
          </div>
        </div>

        {item.options.map(option => {
          return (
            <React.Fragment key={option}>
              {isOpen && (
                <ul className="filterOption">
                  <li className="filterOptionitem">
                    <button>{option}</button>
                  </li>
                </ul>
              )}
            </React.Fragment>
          );
        })}
      </li>
    );
  });
}

注意:如果你的FilterAvailable列表会有动态新增、删除、排序的操作,不要用map遍历的index作为itemKey,必须使用每个item自身稳定的唯一业务id作为标识,避免出现状态错乱的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 22:27:00