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
相关产品推荐
相关产品推荐

