React中如何在array map遍历中正确实现collapsible可折叠内容?
问题根因
你的所有列表条目共用了同一个全局布尔状态showCollapsible,没有和对应条目做绑定,只要状态变更所有条目都会同步执行显隐逻辑,这个问题和你添加的key属性无关:key的作用是帮助React做列表元素的重渲染diff优化,不负责状态的隔离绑定。另外你当前把key加在了button元素上是错误用法,key需要加在map方法返回的最外层根元素上才能生效。
解决方案
方案1:仅允许同时展开1个条目(匹配你描述的需求)
将状态修改为存储当前展开条目的唯一id,点击时更新为当前点击条目的id即可:
import { useState } from "react"; const App = () => { // 初始值为null表示无展开条目,存储当前展开条目的id const [activeId, setActiveId] = useState(null); const myDatas = [ { id: 1, fullName: "John Doe", age: 28, status: "On Duty", }, { id: 2, fullName: "Jane Doe", age: 27, status: "Rest", }, { id: 3, fullName: "James Doe", age: 32, status: "Take a leave", }, ]; return ( <div> {myDatas.map((data) => { return ( // key放在map返回的最外层元素上,用条目自身的id比index更可靠 <div key={data.id}> <p>{data.fullName}</p> <p>{data.age}</p> <button onClick={() => { // 如果点击的是当前已展开的条目,就收起,否则切换为当前点击的条目 setActiveId(activeId === data.id ? null : data.id) }} > Status </button> {/* 仅当前条目的id和激活id匹配时展示status */} {activeId === data.id && <div>{data.status}</div>} </div> ); })} </div> ); }; export default App;
方案2:允许多个条目同时展开
如果需要支持同时展开多个条目,可以将状态改为存储每个条目的展开状态映射:
import { useState } from "react"; const App = () => { // 用对象存储每个id对应条目的展开状态 const [showMap, setShowMap] = useState({}); const myDatas = [ { id: 1, fullName: "John Doe", age: 28, status: "On Duty", }, { id: 2, fullName: "Jane Doe", age: 27, status: "Rest", }, { id: 3, fullName: "James Doe", age: 32, status: "Take a leave", }, ]; return ( <div> {myDatas.map((data) => { return ( <div key={data.id}> <p>{data.fullName}</p> <p>{data.age}</p> <button onClick={() => { setShowMap(prev => ({ ...prev, [data.id]: !prev[data.id] })) }} > Status </button> {showMap[data.id] && <div>{data.status}</div>} </div> ); })} </div> ); }; export default App;
内容的提问来源于stack exchange,提问作者AtomicCommit
相关产品推荐
相关产品推荐

