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

如何在React+TypeScript中用useState实现仅点击图标变红

解决方案

问题根源在于你用了一个全局布尔值iconFavorite控制所有图标状态,所有图标都绑定同一个变量,所以状态一变全跟着变。要实现单个图标独立控制,得给每个列表项维护专属的收藏状态。

方法1:用对象存储已收藏的Item ID

把状态改成对象,用Item的ID作为键,记录每个Item的收藏状态:

import * as React from "react";
import {
  Box,
  Card,
  CardActionArea,
  CardActions,
  CardContent,
  CardMedia,
  Grid,
  Typography
} from "@mui/material";
import FavoriteIcon from "@mui/icons-material/Favorite";
import { ButtonProps } from "./ButtonProps";
import data from "./data/data.json";
import { useState } from "react";

export default function ExemplesCard() {
  // 用对象存储已收藏的item ID,键为id,值为布尔值
  const [favorites, setFavorites] = useState<Record<number, boolean>>({});

  // 切换指定item的收藏状态
  const toggleFavorite = (itemId: number) => {
    setFavorites(prevState => ({
      ...prevState,
      [itemId]: !prevState[itemId]
    }));
  };

  return (
    <Box sx={{ flexGrow: 1, margin: "0 2rem" }}>
      <Grid
        container
        justifyContent="center"
        spacing={{ xs: 8, sm: 8, md: 8, lg: 8, xl: 8 }}
        className="GRID1"
      >
        {data.map((item) => {
          // 判断当前item是否被收藏
          const isFavorite = favorites[item.id] || false;
          return (
            <Grid
              item
              xs={12}
              sm={6}
              md={4}
              lg={3}
              xl={2}
              sx={{
                display: "flex",
                justifyContent: "center",
                marginTop: "1rem"
              }}
              key={item.id} // 把key移到Grid组件上,符合React列表渲染规范
            >
              <Card
                sx={{
                  p: "1rem",
                  boxShadow: 4,
                  maxWidth: {
                    xs: "250px",
                    sm: "250px",
                    md: "280px",
                    lg: "300px",
                    xl: "300px"
                  }
                }}
              >
                <CardActionArea>
                  <CardMedia component="img" height="140" image={item.img} />
                  <CardContent>
                    <Typography gutterBottom variant="h5" component="div">
                      {item.title}
                    </Typography>
                    <Typography variant="body2" color="text.secondary">
                      Lizards are a widespread group of squamate reptiles, with
                      over 6,000 species, ranging across all continents except
                      Antarctica
                    </Typography>
                  </CardContent>
                </CardActionArea>
                <CardActions>
                  <ButtonProps
                    size="small"
                    endIcon={
                      <FavoriteIcon
                        onClick={() => toggleFavorite(item.id)} // 传入当前item的id
                        style={{ color: isFavorite ? "red" : "white" }} // 根据当前item的状态设置颜色
                      />
                    }
                  >
                    Favorite
                  </ButtonProps>
                </CardActions>
              </Card>
            </Grid>
          );
        })}
      </Grid>
    </Box>
  );
}

方法2:用Set存储收藏的ID

如果只需要记录已收藏的ID,用Set会更简洁:

// 初始化状态为Set
const [favoriteIds, setFavoriteIds] = useState<Set<number>>(new Set());

// 切换收藏状态的函数
const toggleFavorite = (itemId: number) => {
  setFavoriteIds(prevSet => {
    const newSet = new Set(prevSet);
    newSet.has(itemId) ? newSet.delete(itemId) : newSet.add(itemId);
    return newSet;
  });
};

// 在渲染时判断当前item是否被收藏
const isFavorite = favoriteIds.has(item.id);

核心改动说明

  • 把全局布尔状态替换为记录每个Item ID的状态集合(对象/Set)
  • 点击事件传入当前Item的ID,仅切换该ID对应的状态
  • 每个图标根据自身Item的状态判断颜色,不再依赖全局变量

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 02:25:44