如何点击列表中Game元素时单独控制对应div的显示与隐藏?
解决方法
你的问题在于当前Redux里的isDivOpen是全局单一状态,所有Game组件共享同一个值,所以点击一个会影响全部。要实现单个Game独立控制展开状态,需要把状态和每个Game的ID绑定,下面提供两种可行方案:
方案一:给每个Game对象添加独立的展开状态
这种方案直接在每个Game数据里维护isDivOpen字段,适合不需要分离状态和业务数据的场景。
修改Redux切片
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; import axios from 'axios'; const initialState = { games: [], isLoading: false, }; // 假设你有获取游戏列表的异步action,返回后给每个游戏初始化isDivOpen export const fetchGames = createAsyncThunk( 'games/fetchGames', async () => { const response = await axios.get('你的游戏列表接口'); // 给每个游戏添加初始展开状态 return response.data.map(game => ({ ...game, isDivOpen: true })); } ); export const gameSlice = createSlice({ name: 'games', initialState, reducers: { toggleSeeMore(state, action) { const gameId = action.payload; // 找到对应ID的游戏,切换它的isDivOpen状态 const targetGame = state.games.find(game => game._id === gameId); if (targetGame) { targetGame.isDivOpen = !targetGame.isDivOpen; } }, }, extraReducers: (builder) => { builder .addCase(fetchGames.pending, (state) => { state.isLoading = true; }) .addCase(fetchGames.fulfilled, (state, action) => { state.isLoading = false; state.games = action.payload; }); }, }) export const { toggleSeeMore } = gameSlice.actions; export default gameSlice.reducer;
修改Game组件
import React from 'react'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import '../../styles/components/Games/Game.css'; import { useSelector, useDispatch } from 'react-redux'; import { toggleSeeMore } from '../../slices/gameSlice'; function Game({ game }) { const { name, description, employees, hours, photo, _id } = game; // 根据当前游戏ID获取对应的展开状态 const isDivOpen = useSelector(state => state.games.find(g => g._id === _id)?.isDivOpen ?? true ); const dispatch = useDispatch() const toggleMenu = () => { dispatch(toggleSeeMore(_id)) } // 注意:你代码里的formattedTimes需要提前定义,这里保留原结构 return ( <div className='game_card'> <div className="game_heading"> <div className="image_container"> <img src={`http://localhost:5000/uploads/${photo}`} alt="no photo" /> </div> <h1>{name}</h1> </div> <div className="game_content"> <p className="description">{description}</p> <div className="game_hours"> {formattedTimes.map((time, index) => ( <div key={index}>{time}</div> ))} </div> </div> <button onClick={toggleMenu}>See More<ExpandMoreIcon/></button> <div className={`employees ${isDivOpen ? 'show' : 'hide'}`}> <p>Employees</p> {employees.map((employee, index) => ( <div key={index}>{employee}</div> ))} </div> </div> ); } export default Game;
方案二:单独维护展开状态映射表
这种方案把展开状态和游戏数据分离,用一个对象记录每个游戏ID对应的展开状态,更适合需要独立管理UI状态的场景。
修改Redux切片
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; import axios from 'axios'; const initialState = { games: [], isLoading: false, expandedGames: {}, // 结构:{ [gameId]: boolean } }; export const fetchGames = createAsyncThunk( 'games/fetchGames', async () => { const response = await axios.get('你的游戏列表接口'); return response.data; } ); export const gameSlice = createSlice({ name: 'games', initialState, reducers: { toggleSeeMore(state, action) { const gameId = action.payload; // 切换对应ID的展开状态,未记录时默认展开(true) state.expandedGames[gameId] = !state.expandedGames[gameId] ?? true; }, }, extraReducers: (builder) => { builder .addCase(fetchGames.pending, (state) => { state.isLoading = true; }) .addCase(fetchGames.fulfilled, (state, action) => { state.isLoading = false; state.games = action.payload; }); }, }) export const { toggleSeeMore } = gameSlice.actions; export default gameSlice.reducer;
修改Game组件
import React from 'react'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import '../../styles/components/Games/Game.css'; import { useSelector, useDispatch } from 'react-redux'; import { toggleSeeMore } from '../../slices/gameSlice'; function Game({ game }) { const { name, description, employees, hours, photo, _id } = game; // 从expandedGames映射表中获取当前游戏的展开状态,默认展开 const isDivOpen = useSelector(state => state.games.expandedGames[_id] ?? true ); const dispatch = useDispatch() const toggleMenu = () => { dispatch(toggleSeeMore(_id)) } // 注意:你代码里的formattedTimes需要提前定义,这里保留原结构 return ( <div className='game_card'> <div className="game_heading"> <div className="image_container"> <img src={`http://localhost:5000/uploads/${photo}`} alt="no photo" /> </div> <h1>{name}</h1> </div> <div className="game_content"> <p className="description">{description}</p> <div className="game_hours"> {formattedTimes.map((time, index) => ( <div key={index}>{time}</div> ))} </div> </div> <button onClick={toggleMenu}>See More<ExpandMoreIcon/></button> <div className={`employees ${isDivOpen ? 'show' : 'hide'}`}> <p>Employees</p> {employees.map((employee, index) => ( <div key={index}>{employee}</div> ))} </div> </div> ); } export default Game;
两种方案都能实现单个Game独立控制展开状态,你可以根据自己的业务场景选择。
内容的提问来源于stack exchange,提问作者tukitooo1998
相关产品推荐
相关产品推荐

