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

React中点击观看图标仅禁用对应卡片收藏图标的问题求助

解决点击已观看图标后仅禁用当前卡片收藏图标的问题

你当前的问题核心是用全局Redux状态value控制所有Star组件的禁用状态,点击任意Eye图标都会修改这个全局值,导致所有卡片的Star都被禁用。正确的做法是通过watched数组判断当前动漫是否已被标记为已观看,仅对当前卡片的Star生效。

具体修改步骤

1. 清理Redux切片中的无用状态与Action

删除value相关的全局状态,以及add_occupied、remove_occupied这两个无关Action,我们将用watched数组来判断状态。

修改后的animeSlice.js:

import { createSlice } from "@reduxjs/toolkit";

const initialState = {
    favourite: [],
    watched: [],
    page: ""
};

const animeSlice = createSlice({
    name: "anime",
    initialState,
    reducers: {
        add_favourite(state, { payload }) {
            state.favourite.push(payload);
        },
        remove_favourite(state, { payload }) {
            state.favourite = state.favourite.filter(
                (anime) => anime?.mal_id !== payload
            );
        },
        add_watched(state, { payload }) {
            state.watched.push(payload);
        },
        remove_watched(state, { payload }) {
            state.watched = state.watched.filter((anime) => anime?.mal_id !== payload);
        },
        pageNumber(state, { payload }) {
            state.page = payload
        }
    },
});

export const {
    add_favourite,
    remove_favourite,
    add_watched,
    remove_watched,
    pageNumber
} = animeSlice.actions;
export default animeSlice.reducer;

2. 修改Eye组件,同步本地与Redux状态

让Eye组件的本地状态与Redux的watched数组保持同步,移除和occupied相关的dispatch操作。

修改后的Eye.js:

import { useState, useEffect } from "react";
import { BsEyeSlash, BsEyeFill } from "react-icons/bs";
import { useDispatch, useSelector } from "react-redux";
import { add_watched, remove_watched } from "../features/animeSlice";

const Eye = ({ anime }) => {
    const dispatch = useDispatch();
    const watchedAnimes = useSelector(state => state.anime.watched);
    // 初始化时检查当前动漫是否在已观看列表
    const [active_eye, setActive_eye] = useState(watchedAnimes.some(item => item.mal_id === anime.mal_id));

    useEffect(() => {
        // 已观看列表变化时自动更新本地状态
        setActive_eye(watchedAnimes.some(item => item.mal_id === anime.mal_id));
    }, [watchedAnimes, anime.mal_id]);

    const toggle_eye = () => {
        if (!active_eye) {
            dispatch(add_watched(anime));
        } else {
            dispatch(remove_watched(anime?.mal_id));
        }
    };

    return (
        <div>
            {!active_eye ? (
                <BsEyeSlash
                    className="text-xl text-green-500 icons_1"
                    onClick={toggle_eye}
                />
            ) : (
                <BsEyeFill
                    className="text-xl text-red-500 icons_1"
                    onClick={toggle_eye}
                />
            )}
        </div>
    );
};

export default Eye;

3. 修改Star组件,基于watched数组判断禁用状态

Star组件不再读取全局value,而是检查当前动漫是否在watched数组中,以此决定是否禁用点击和灰化图标。

修改后的Star.js:

import { useState, useEffect } from "react";
import { AiOutlineStar, AiFillStar } from "react-icons/ai";
import { add_favourite, remove_favourite } from "../features/animeSlice";
import { useDispatch, useSelector } from "react-redux";

const Star = ({ anime }) => {
    const dispatch = useDispatch();
    const favouriteAnimes = useSelector(state => state.anime.favourite);
    const watchedAnimes = useSelector(state => state.anime.watched);
    // 初始化收藏状态:检查当前动漫是否在收藏列表
    const [active_star, setActive_star] = useState(favouriteAnimes.some(item => item.mal_id === anime.mal_id));
    // 判断当前动漫是否已被标记为已观看
    const isWatched = watchedAnimes.some(item => item.mal_id === anime.mal_id);

    useEffect(() => {
        // 收藏列表变化时更新本地状态
        setActive_star(favouriteAnimes.some(item => item.mal_id === anime.mal_id));
    }, [favouriteAnimes, anime.mal_id]);

    const toggle_star = () => {
        if (!active_star) {
            dispatch(add_favourite(anime));
        } else {
            dispatch(remove_favourite(anime?.mal_id));
        }
    };

    return (
        <div>
            {!active_star ? (
                <AiOutlineStar
                    className={
                        isWatched
                            ? "text-xl text-gray-300 pointer-events-none"
                            : "text-xl text-yellow-500 icon_1"
                    }
                    onClick={toggle_star}
                />
            ) : (
                <AiFillStar
                    className={
                        isWatched
                            ? "text-xl text-gray-300 pointer-events-none"
                            : "text-xl text-yellow-500 icon_1"
                    }
                    onClick={toggle_star}
                />
            )}
        </div>
    );
};
export default Star;

4. 更新TopAnime组件的Eye调用

移除Eye组件的type="occupied"参数,因为已经不需要这个属性了:

<Eye anime={anime} />

修改完成后,点击任意卡片的Eye图标,只会禁用当前卡片的Star组件,其他卡片不受影响,完全符合需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 07:55:37