React中map渲染列表点击时仅控制被点击div显隐
问题根因
当前展开/收起状态定义在UserBlock父组件层级,是所有渲染卡片共享的单一全局状态:所有卡片的详情区显隐、按钮文案都绑定这同一个状态值,点击任意按钮修改状态时,所有卡片都会同步重新渲染、响应同一个状态变化,自然会出现全部同步展开/收起的问题。
修复方法
最简洁的实现是把单张用户卡片抽为独立组件,让每个卡片维护自己的展开状态,互相完全隔离。修复后完整代码如下:
import React, { useState } from 'react' // 抽离单张用户卡片组件,每个实例独立维护自己的展开状态 const UserCard = ({ user, index }) => { const infoTitle = `font-bold` const [isExpanded, setIsExpanded] = useState(false) const toggleExpand = () => { setIsExpanded(prev => !prev) } return ( <div className="bg-gray-900 text-white m-2 p-10 w-full rounded-2xl shadow-lg m-8 md:w-1/4 lg:w-1/6"> <p className={`${infoTitle} text-xl`}>username: {user.name}</p> {/* 直接根据当前卡片的isExpanded状态控制显隐 */} {isExpanded && ( <div> <p className={infoTitle}>email: {user.email}</p> <p className={infoTitle}>website: {user.website}</p> <p className={infoTitle}>phone: {user.phone}</p> <p className={infoTitle}>address:</p> <p className={infoTitle}>suite: {user.address.suite}</p> <p className={infoTitle}>street: {user.address.street}</p> <p className={infoTitle}>city: {user.address.city}</p> <p className={infoTitle}>zipcode: {user.address.zipcode}</p> </div> )} <div> <button onClick={toggleExpand}> View {isExpanded ? "Less" : "More"} </button> </div> </div> ) } const UserBlock = (props) => { return ( <div className='flex flex-wrap w-full justify-center '> {props.userArray.map((user, index) => ( <UserCard key={index} user={user} index={index} /> ))} </div> ) } export default UserBlock
优化点说明
- 移除了冗余的
viewMoreClass状态:直接通过当前卡片的展开状态判断是否渲染详情区,不需要额外维护class字符串,逻辑更简洁 - 修正原代码拼写错误:将语义模糊、拼写错误的
laodMoreClicked改为更易读的isExpanded - 状态更新采用函数式写法
setIsExpanded(prev => !prev),避免闭包导致的状态值不同步问题 - 移除了按钮文案里多余的索引拼接,符合常规交互的文案逻辑
如果你不想抽离额外组件,也可以在父组件用集合存储展开的卡片索引,核心逻辑参考:
const [expandedIndexSet, setExpandedIndexSet] = useState(new Set()) const toggleExpand = (index) => { setExpandedIndexSet(prev => { const newSet = new Set(prev) newSet.has(index) ? newSet.delete(index) : newSet.add(index) return newSet }) } // 渲染时判断 expandedIndexSet.has(index) 控制详情显隐,按钮点击传入对应index即可 // 这种方案更适合需要从父组件外部控制卡片展开状态的场景
内容的提问来源于stack exchange,提问作者Zian Ejaz
相关产品推荐
相关产品推荐

