Reputation: 118
So for some reason, it seems that the equipItemById reducer below is mutating state - despite it being basically verbatim from the Redux Toolkit example:
Full slice below:
import { createSlice } from '@reduxjs/toolkit';
import Item from '../../../Entities/Item/Item';
const initialState = {
itemsById: [
new Item('weapon', 'oak_stave', 0),
new Item('chest', 'basic_robes', 0),
new Item('feet', 'basic_boots', 0),
new Item('head', 'basic_circlet', 0),
new Item('consumable', 'potion_of_healing', 0),
new Item('consumable', 'potion_of_healing', 1),
new Item('consumable', 'potion_of_healing', 1),
new Item('weapon', 'rusty_sword', 5),
new Item('weapon', 'iron_sword', 5),
new Item('weapon', 'steel_sword', 5),
new Item('weapon', 'enchanted_steel_sword', 5),
],
inTrade: false,
actorInTradeById: undefined,
itemsPlayerWantsToTradeById: [],
itemsOtherActorWantsToTrade: [],
itemsByLocationName: {
centralSquare: [new Item('weapon', 'enchanted_steel_sword')],
},
};
const itemSlice = createSlice({
name: 'items',
initialState: initialState,
reducers: {
addItemToActorFromLocationByIdAndName: (state, action) => {
const { actorId, item } = action.payload;
let itemCopy = item;
item.ownerId = actorId;
state.itemsById.push(itemCopy);
},
equipItemById: (state, action) => {
const item = state.itemsById.find((item) => item.id === action.payload);
item.equipped = true;
},
unequipItemById: (state, action) => {
const { itemId } = action.payload;
const item = state.itemsById.find((item) => item.id === itemId);
item.equipped = false;
},
dropItemFromInventory: (state, action) => {
const { itemId, locationName } = action.payload;
const item = state.itemsById.find(
(item) => item.id === itemId
);
item.ownerId = undefined;
item.equipped = false;
state.itemsById = state.itemsById.filter(item => item.id !== itemId);
state.itemsByLocationName[locationName].push(item);
},
removeItemFromLocation: (state, action) => {
const { itemId, locationName } = action.payload;
state.itemsByLocationName[locationName] = state.itemsByLocationName[
locationName
].filter((item) => item.id !== itemId);
},
},
});
export const {
addItemToActorFromLocationByIdAndName: addItemToActorById,
equipItemById,
unequipItemFromActorByIds,
inventorySetActiveItem,
equippedSetActiveItem,
dropItemFromInventory,
dropItemFromEquipped,
removeItemFromLocation,
} = itemSlice.actions;
export default itemSlice;
Dispatch is called as :
dispatch(
itemSlice.actions.equipItemById(props.item.id)
);
And as you can see below - the action in question has the equipped property as the same both before and after - even though it's definitely false before.
an Item object simply looks like this (and is nested inside the itemsById array)
{
'0': {
type: 'weapon',
id: 0,
qty: 1,
equipped: true,
ownerId: 0,
name: 'Oak Branch',
icon: 'fa-staff',
rarity: 0,
descDetails: 'Deals an additional 1 damage per hit.',
desc: 'A simple weapon. Strong and sturdy. No man turns down a stout wooden branch, when the alternative is an empty hand to face the sharp steel of a bandit.',
stats: {},
value: 1,
slot: 'weapon_main',
addedDmgString: '1'
}
}
Upvotes: 0
Views: 167
Reputation: 44078
immer
does not work on class instances by default. You can mark them as immerable
though.
But generally, you should not put class instances in your Redux store in the first place, see the Redux Style Guide
Upvotes: 4