如何通过onClick控制映射列表中对应ul元素的显示状态?
解决方案
核心思路
不用给每个元素单独加state,用一个统一的state来记录哪些项是展开状态——你已经用obj.name作为每个项的唯一key,刚好可以用它来标识每个需要切换的项。
两种实用实现方案
方案1:单次仅展开一个项(点击新项自动收起旧项)
适合需要互斥展开的场景:
import { useState } from 'react'; function YourComponent() { // 存储当前展开的项名称,初始为null表示全部收起 const [expandedItem, setExpandedItem] = useState(null); // 假设myData是从API获取的数组数据 return ( <div> {myData.map((obj) => ( <div style={{ maxWidth: "500px", marginLeft: "25%" }} key={obj.name}> <img src={obj.image} width="500px" alt={obj.name} /> <h1>{obj.name}</h1> <h2 onClick={() => { // 切换逻辑:当前项已展开就收起,否则展开;点击其他项自动替换当前展开项 setExpandedItem(prev => prev === obj.name ? null : obj.name); }} style={{ cursor: 'pointer' }} // 加鼠标样式提示可点击 > Ingredients </h2> {/* 根据state判断是否显示ul */} <ul style={{ display: expandedItem === obj.name ? 'block' : 'none' }}> {obj.ingredients.map((ingredient, idx) => ( {/* 用唯一且稳定的key,别用Math.random() */} <li key={`${obj.name}-ing-${idx}`}>{ingredient}</li> ))} </ul> </div> ))} </div> ); }
方案2:支持同时展开多个项
如果需要多个ul同时显示,用Set存储所有展开的项名称:
import { useState } from 'react'; function YourComponent() { // 用Set存储所有展开的项名称,初始为空表示全部收起 const [expandedItems, setExpandedItems] = useState(new Set()); // 抽离切换逻辑,代码更整洁 const toggleExpand = (itemName) => { setExpandedItems(prev => { const newSet = new Set(prev); newSet.has(itemName) ? newSet.delete(itemName) : newSet.add(itemName); return newSet; }); }; return ( <div> {myData.map((obj) => ( <div style={{ maxWidth: "500px", marginLeft: "25%" }} key={obj.name}> <img src={obj.image} width="500px" alt={obj.name} /> <h1>{obj.name}</h1> <h2 onClick={() => toggleExpand(obj.name)} style={{ cursor: 'pointer' }} > Ingredients </h2> <ul style={{ display: expandedItems.has(obj.name) ? 'block' : 'none' }}> {obj.ingredients.map((ingredient, idx) => ( <li key={`${obj.name}-ing-${idx}`}>{ingredient}</li> ))} </ul> </div> ))} </div> ); }
关键注意点
- 别用
Math.random()生成key,每次渲染都会生成新值,会导致组件频繁重渲染甚至丢失状态,用obj.name+索引的组合足够唯一且稳定 - 默认隐藏ul的逻辑通过初始state(
null或空Set)配合display: none实现,无需额外处理 - 可以根据需求给h2加展开/收起的文字提示(比如
Ingredients ▼/Ingredients ▲),提升交互体验
内容的提问来源于stack exchange,提问作者Sporadic
相关产品推荐
相关产品推荐

