React中如何在map函数中控制单个元素状态,实现多Tab独立展开
实现多Tab独立展开/收起的解决方案
你的问题根源在于所有Tab共用了同一个isOpen布尔状态,点击任意Tab时,这个全局状态会同时控制所有内容的显示/隐藏。要实现多Tab独立开关,需要为每个Tab单独维护展开状态,以下是具体实现方案:
核心思路
将单个布尔状态isOpen替换为记录每个Tab展开状态的对象(或Set集合),通过Tab的唯一标识(这里用item.id)区分不同Tab的状态。
修改后的代码
import React, { useEffect, useState } from 'react' import axios from 'axios'; import LeaguesStyle from '../components/styles/LeaguesStyle.css'; const Leagues = () => { const [teamz, setTeams] = useState([]); const [loading, setLoading] = useState(false) // 用对象存储每个Tab的展开状态,key为team的id,value为布尔值 const [openTabs, setOpenTabs] = useState({}); const getTeams = async () => { try { const res = await axios.get('https://api-football-standings.azharimm.site/leagues'); setTeams(res.data.data) setLoading(true); } catch (err) { alert(err.message) } } useEffect(() => { getTeams(); }, []); // 切换指定Tab的展开状态 const toggleTab = (id) => { setOpenTabs(prevState => ({ ...prevState, [id]: !prevState[id] // 反转当前Tab的状态 })) } return ( <div className="leagues"> {loading && teamz.map(item => ( <div className='teamCard' key={item.id}> <div onClick={() => toggleTab(item.id)} className="teamDiv"> <img src={item.logos.dark} className='teamLogo' /> <h1>{item.name}</h1> </div> {/* 根据当前Tab的id判断是否显示内容 */} {openTabs[item.id] && <div className='card-content-active'>{item.abbr}</div>} </div> ))} </div> ); }
关键修改点说明
- 状态结构调整:把
isOpen: boolean改成openTabs: { [id: string]: boolean },每个Tab的id对应一个独立的展开状态。 - 点击事件优化:新增
toggleTab函数,通过函数式更新状态,确保基于最新状态修改,避免状态覆盖问题。 - 内容渲染判断:不再依赖全局的
isOpen,而是检查openTabs[item.id]的值决定是否显示当前Tab内容。
可选方案:使用Set集合
如果觉得对象结构不够直观,也可以用Set存储已展开的Tab id:
const [openTabIds, setOpenTabIds] = useState(new Set()); const toggleTab = (id) => { setOpenTabIds(prevSet => { const newSet = new Set(prevSet); newSet.has(id) ? newSet.delete(id) : newSet.add(id); return newSet; }) } // 渲染时判断 {openTabIds.has(item.id) && <div className='card-content-active'>{item.abbr}</div>}
这种方案逻辑更清晰,适合只需要记录“是否展开”的场景。
内容的提问来源于stack exchange,提问作者orrigenda
相关产品推荐
相关产品推荐

