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

ReactJS map渲染列表时如何通过onClick单独控制单个卡片展开

问题根源

所有卡片共用了同一个布尔类型的expanded状态,状态变更时所有卡片的展开判断逻辑同步生效,自然会出现全展开/全收起的问题,无法区分单个卡片的独立状态。

修复步骤

1. 调整状态定义与数据获取逻辑

不再用布尔值存全局展开状态,改为存储当前展开卡片的唯一ID,同时在拉取Firestore数据时把文档ID注入到项目数据中,作为每个卡片的唯一标识:

export const NFTprojects = () => {
  // 存储当前展开的卡片ID,默认值为null即无卡片展开
  const [expandedId, setExpandedId] = useState(null);
  const [projects, setProjects] = useState([]);

  const ref = firebase.firestore().collection("NFTprojects");

  function getProjects() {
    ref.onSnapshot((querySnapshot) => {
      const items = [];
      querySnapshot.forEach((doc) => {
        // 注入文档唯一ID
        items.push({ id: doc.id, ...doc.data() });
      });
      setProjects(items);
    });
  }

  useEffect(() => {
    getProjects();
  }, []);

  // 展开点击逻辑:点击已展开的卡片则收起,否则展开当前点击卡片
  const handleExpandClick = (projectId) => {
    setExpandedId(expandedId === projectId ? null : projectId);
  };

  // 其余return渲染逻辑按后续步骤修改

2. 修改渲染部分的展开判断逻辑

在map渲染卡片时,把原来直接绑定全局expanded的地方,改为判断当前卡片ID和expandedId是否一致,同时点击事件传入当前卡片ID:

{projects.map((project) => (
  <Grid item xs={4} key={project.id}>
    <Card sx={{ maxWidth: 400, borderRadius: 3, mb: 5 }}>
      {/* 上方CardMedia、CardContent、CardActions里的IconButton、Button部分代码保持不变 */}

      <ExpandMore
        expand={expandedId === project.id}
        onClick={() => handleExpandClick(project.id)}
        aria-expanded={expandedId === project.id}
        aria-label="show more"
      >
        <ExpandMoreIcon />
      </ExpandMore>

    </CardActions>

    {/* Collapse的in属性同样改为ID判断 */}
    <Collapse in={expandedId === project.id} timeout="auto" unmountOnExit>
      <CardContent>
        <Typography variant="h6" sx={{ fontWeight: 'bold' }} style={{ fontFamily: 'Merriweather' }}>Job Description:</Typography>
        <Typography paragraph>
          {project.jobDesc}
        </Typography>
        <Typography variant="h6" sx={{ fontWeight: 'bold' }}>Prerequisites</Typography>
        <Typography paragraph>
          {project.jobPrereq}
        </Typography>
      </CardContent>
    </Collapse>
    </Card>
  </Grid>
))}
逻辑说明
  • 修改后同一时间只会展开一个卡片,点击其他卡片会自动收起之前展开的卡片,展开当前点击项
  • 如果需要支持多卡片同时展开,只需要把expandedId改为数组类型状态,点击时做ID的增删判断即可
  • 给循环渲染的Grid项加上key={project.id},可避免React渲染告警

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 13:15:40