I have a list of elements where each element is a Game
and as I toggle I dispatch an action to my slice where I want to affect the value of isDivOpen
but just for the element (Game
) I clicked on.
I created the following slice:
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
const initialState = {
games: [],
isLoading: false,
isDivOpen: true,
};
export const gameSlice = createSlice({
name: 'games',
initialState,
reducers: {
toggleSeeMore(state, action) {
const gameId = action.payload;
console.log(gameId);
},
},
})
export const { toggleSeeMore } = gameSlice.actions;
export default gameSlice.reducer;
And the following is my component:
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 } = game;
const isDivOpen = useSelector(state => state.games.isDivOpen);
const dispatch = useDispatch()
const toggleMenu = () => {
const gameId = game._id
dispatch(toggleSeeMore(gameId))
}
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;
I am receiving the correct id of the game I'm clicking on, but I don't know how to change the value of isDivOpen
just for that game.
You are on the right track. Instead of using isDivOpen
as a boolean value though, you should store the passed gameId
or null when deselecting the game. The UI will check the current openGameId
value against its own game id value, and set the appropriate conditional value.
Example:
const initialState = {
games: [],
isLoading: false,
openGameId: null,
};
export const gameSlice = createSlice({
name: 'games',
initialState,
reducers: {
toggleSeeMore(state, action) {
const gameId = action.payload;
// Toggles openGameId to gameId if not equal to current state,
// otherwise openGameId is toggled back to null to deselect
state.openGameId = state.openGameId === gameId ? null : gameId;
},
},
})
function Game({ game }) {
const dispatch = useDispatch();
const { openGameId } = useSelector(state => state.games);
const { _id: gameId, name, description, employees, hours, photo } = game;
// Compute if this game is open
const gameIsOpen = openGameId === gameId;
const toggleMenu = () => {
dispatch(toggleSeeMore(gameId));
}
return (
<div className='game_card'>
...
<button onClick={toggleMenu}>
See More<ExpandMoreIcon />
</button>
<div className={`employees ${gameIsOpen ? 'show' : 'hide'}`}>
...
</div>
</div>
);
}
export default Game;