So im using redux for state management for a React App. I’m getting some data from my API and set the response to the state.
State object looks like this:
export type TrendingState = [{
id: string;
points: number;
name: string;
}]
Initial value is set to empty strings and 0 for the number prop:
const initialState: TrendingState = [
{
id: '',
points: 0,
name: '',
},
];
Finally im using store to create a slice for dispatching the method in my component:
export const trendingSlice = createSlice({
name: 'trending',
initialState,
reducers: {
setTrendingPlayers: (state, action: PayloadAction<TrendingState>) => {
Object.assign(state, action.payload);
state = action.payload;
//console log the state to see what it looks like
console.log(state);
},
}
},
);
export const { setTrendingPlayers } = trendingSlice.actions;
export default trendingSlice.reducer;
Now in my component i can use id and name in my functions just fine but the number prop returns undefined. When i log the state as a whole it does show that number actually has a value for every object. I’m thinking that in some way i’m probably trying to use number before load but it is being used in the same mapping as name and id, so why arent they undefined aswell?
My component as a whole:
import { useAppSelector } from "../context/hooks";
import { useAppDispatch } from "../context/hooks";
import api from "../api";
import { SetStateAction, useEffect, useState } from "react";
import { setTrendingPlayers } from "../context/trendingSlice";
import { getPlayerImage } from "../constants/Images";
function Home() {
const playerState = useAppSelector(state => state.player);
const trendingState = useAppSelector(state => state.trending);
const dispatch = useAppDispatch();
const [points, setPoints] = useState(0);
async function getTrendingPlayers(){
dispatch(setTrendingPlayers(await api.getTrendingPlayers()));
}
useEffect(() => {
getTrendingPlayers();
}, [])
const logo = require('../assets/defaulticon.png')
return (
<>
<section>
<div className='header-image'>
<div className='header-content'>
</div>
</div>
<h2 className="trending-titleh2">TRENDANDE SPELARE</h2>
<h3 className="trending-titleh3">SENASTE 5 MATCHERNA</h3>
<div className='trending-players'>
{trendingState.map((player, index) => {
if (index < 3) {
return (
<div className='trending-player-box'>
<div className="trendinglogo">
{getImage(player.id)}
</div>
<h3>{player.name!.split(",")[1]} {player.name!.split(",")[0]}</h3>
<h3>{player.points}</h3>
</div>
)
}
})}
</div>
<div className='shl-news'>
<div className='shl-news-box'>
</div>
</div>
</section>
</>
);
}
function getImage(id: string) {
return getPlayerImage(id);
}
export default Home;
I’m probably missing something obvious here but any help from some non-tired eyes would be appreciated 🙂
>Solution :
It looks like the issue is with the code that sets the state in the setTrendingPlayers reducer.
When using Object.assign to update the state, the first argument is the target object, which in this case is the current state. The second argument is the source object, which is the action.payload. However, Object.assign only updates the enumerable properties of the target object, and it does not modify the original object. Instead, it returns a new object.
You are then overwriting the value of state with the value of action.payload, but the original state object is not modified. You can fix this by using the return value of Object.assign instead of overwriting state.
Here is how you can update the setTrendingPlayers reducer to fix the issue:
setTrendingPlayers: (state, action: PayloadAction<TrendingState>) => {
// Use the return value of Object.assign to update the state
return Object.assign(state, action.payload);
// Remove this line, since it overwrites the value of state
// state = action.payload;
//console log the state to see what it looks like
console.log(state);
},
I hope this helps!