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

React+Material UI中卡片下拉菜单同步展开问题求助

问题原因

所有卡片共用了同一个expanded状态变量,点击任意卡片的展开按钮时,全局状态会被修改,导致所有绑定该状态的卡片同步展开/收起。

解决方案:抽离独立卡片组件

把单张卡片封装成独立组件,让每个组件自己管理展开状态,实现卡片间的独立控制。

优化后的代码如下:

const ExpandMore = styled((props) => {
  const { expand, ...other } = props;
  return <IconButton {...other} />;
})(({ theme, expand }) => ({
  transform: !expand ? 'rotate(0deg)' : 'rotate(180deg)',
  marginLeft: 'auto',
  transition: theme.transitions.create('transform', {
    duration: theme.transitions.duration.shortest,
  }),
}));

// 独立卡片组件,自带状态管理
function BlogCard({ title, subheader, imageUrl, previewText, detailContent }) {
  const [expanded, setExpanded] = React.useState(false);

  const handleExpandClick = () => {
    setExpanded(!expanded);
  };

  return (
    <Box m={6}>
      <Card sx={{ maxWidth: 345 }}>
        <CardHeader
          title={title}
          subheader={subheader}
        />
        <CardMedia
          component="img"
          height="194"
          image={imageUrl}
          alt="Blog cover"
        />
        <CardContent>
          <Typography variant="body1" color="text.secondary">
            {previewText}
          </Typography>
        </CardContent>
        <CardActions disableSpacing>
          <ExpandMore
            expand={expanded}
            onClick={handleExpandClick}
            aria-expanded={expanded}
            aria-label="show more"
          >
            <ExpandMoreIcon />
          </ExpandMore>
        </CardActions>
        <Collapse in={expanded} timeout="auto" unmountOnExit>
          <CardContent>
            {detailContent}
          </CardContent>
        </Collapse>
      </Card>
    </Box>
  );
}

function Blogs(){
    // 卡片数据统一管理,新增卡片只需添加数据项
    const blogData = [
      {
        title: "It’s a cocktail o’clock.",
        subheader: "May 14, 2021",
        imageUrl: "https://img.freepik.com/free-photo/selection-various-cocktails-table_140725-2909.jpg?w=2000",
        previewText: "Beat The Heat With Chilled Cocktails At The Best Bars In New York.",
        detailContent: (
          <>
            <Typography paragraph>To a foodie, summer means one thing and one thing only – DRINKS!</Typography>
            <Typography paragraph>
            Yes people, we know it’s hot out there and the only way to quench your thirst is by guzzling down a bunch of ice-cold cocktails
            </Typography>
            <Typography paragraph>
              <h4>1.The Bar Room at The Beekman</h4>
              Visit the beautiful Bar Room in the historic Beekman Hotel for high-key romance that really wows.
              Do try the whiskey sour.One of the best drinks available.
              <h4>2.Dublin House</h4>
              You can never go wrong with Sláinte! Margarita,Pot O'Gold, & Irish Old Fashioned
            <h4>3.Russian Samovar</h4>
            Alpensahne,Amarula Cream Liqueur, Caribou,Feni
            </Typography>
          </>
        )
      },
      {
        title: "Winner Winner Pizza Dinner",
        subheader: "May 14, 2021",
        imageUrl: "https://cdn.shopify.com/s/files/1/0624/9853/articles/20220211142645-margherita-9920.jpg?crop=center&height=800&v=1660843558&width=800",
        previewText: "Beat The Heat With Chilled Cocktails At The Best Bars In New York.",
        detailContent: (
          <>
            <Typography paragraph>To a foodie, summer means one thing and one thing only – DRINKS!</Typography>
            <Typography paragraph>
            Yes people, we know it’s hot out there and the only way to quench your thirst is by guzzling down a bunch of ice-cold cocktails
            </Typography>
            <Typography paragraph>
              <h4>1.The Bar Room at The Beekman</h4>
              Visit the beautiful Bar Room in the historic Beekman Hotel for high-key romance that really wows.
              Do try the whiskey sour.One of the best drinks available.
              <h4>2.Dublin House</h4>
              You can never go wrong with Sláinte! Margarita,Pot O'Gold, & Irish Old Fashioned
            <h4>3.Russian Samovar</h4>
            Alpensahne,Amarula Cream Liqueur, Caribou,Feni
            </Typography>
          </>
        )
      }
    ];

    return (
      <>
        <Grid container direction="row" justifyContent="center">
          {blogData.map((blog, index) => (
            <Grid item xs={4} key={index}>
              <BlogCard 
                title={blog.title}
                subheader={blog.subheader}
                imageUrl={blog.imageUrl}
                previewText={blog.previewText}
                detailContent={blog.detailContent}
              />
            </Grid>
          ))}
        </Grid>
      </>
    );
}
方案说明
  • 每个BlogCard组件内部维护独立的expanded状态,点击展开按钮仅影响当前卡片
  • 卡片数据统一存入数组,通过map循环渲染,减少重复代码,后续新增卡片只需添加数据项
  • 保留原有UI样式和交互逻辑,同时提升代码的可维护性和扩展性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 23:20:31