我的 Redux 状态没有更新 - 即使旧的新状态不相等



我的 Redux 状态有问题。我做了一个应该更新数组中值的化简器。但是,我相信已经遵循了所有不变性原则,但由于某种原因,我的状态没有更新。我什至在我的化简器的末尾添加了一个控制台日志,比较旧的 en 新状态,它返回 false。

我错过了什么吗?

我正在使用Redux DevTools chrome插件来检查状态。

州:

selectedProfileId: mainProfileId,
profiles: {
[mainProfileId]:{
name: "Spellbook 1",
classes: [],
learnedSpells: {
cantrip: [],
first: [],
second: [],
third: [],
fourth: [],
fifth: [],
sixth: [],
seventh: [],
eighth: [],
ninth: []
},
spellSlots:[
{slots: 0, used: 0},
{slots: 0, used: 0},
{slots: 0, used: 0},
{slots: 0, used: 0},
{slots: 0, used: 0},
{slots: 0, used: 0},
{slots: 0, used: 0},
{slots: 0, used: 0},
{slots: 0, used: 0}
]
}
}

还原剂:

switch (action.type) {
case actions.SET_SPELL_SLOTS:    
let newSpellSlotArray = state.profiles[state.selectedProfileId].spellSlots.slice();
newSpellSlotArray.map((item, index) => {
if (index !== action.spellslot-1) {
return item
}
let newItem = {
...item,
slots: parseInt(action.count)
};
console.log("Updating item:", item, newItem);
return newItem;
})
var newState = {
...state,
profiles: {
...state.profiles,
[state.selectedProfileId]:{
...state.profiles[state.selectedProfileId],
spellSlots: newSpellSlotArray
}
}
}
console.log((newState == state))
return newState
default:
return state
}

控制台日志:

Updating item: {slots: 0, used: 0}
slots: 0
used: 0
__proto__: Object 
{slots: 5, used: 0}
slots: 5
used: 0
__proto__: Object
spellbookData.js:70
false

您的化简器已损坏,因为您实际上并没有使用新值保存数组。

  • spellSlots.slice()确实会创建一个包含所有旧值的新数组引用
  • 但是,newSpellSlotArray.map()返回一个新的数组引用,其中包含map()回调返回的所有值,但您的代码当前通过不将其分配给变量而丢弃该新数组。
  • 在 return 语句中,spellSlots: newSpellSlotArray将返回一个包含所有旧数据的新数组,而不是更新的数据。

代码的短期修复将是:

const newSpellSlotArray = state.profiles[state.selectedProfileId].spellSlots.map( (item, index) => {
// map logic here
});

但是,我强烈建议您改用我们的官方 Redux 工具包包。 RTK的createSliceAPI在内部使用Immer,它允许你编写"变异"的不可变更新。 这将使您将整个减速器简化为:

const profilesSlice= createSlice({
name: "profiles",
initialState,
reducers: {
spellSlotsUpdated(state, action) {
const {spellslot, count} = action.payload;
const item = state.profiles[state.selectedProfileId].spellSlots[spellslot- 1];
item.slots = parseInt(count);
}
}  
})

如您所见,这更短,更易于阅读。

修改你的Reducer,Array.map((返回你必须存储和使用的新数组

switch (action.type) {
case actions.SET_SPELL_SLOTS:    
let newSpellSlotArray = state.profiles[state.selectedProfileId].spellSlots.map((item, index) => {
if (index !== action.spellslot-1) {
return item
}
let newItem = {
...item,
slots: parseInt(action.count)
};
console.log("Updating item:", item, newItem);
return newItem;
})
var newState = {
...state,
profiles: {
...state.profiles,
[state.selectedProfileId]:{
...state.profiles[state.selectedProfileId],
spellSlots: newSpellSlotArray
}
}
}
console.log((newState == state))
return newState
default:
return state
}

最新更新