我正在使用immer(通过redux-toolkit
中的createSlice
(来管理redux应用程序中的状态。我已经写了一个reducer,它接收音乐曲目的有效负载,并将它们添加到用户库中。在某种程度上,这个减速器还必须为每个曲目创建艺术家条目。
createTracks(draft, action: PayloadAction<{ tracks: Array<ITrack> | ITrack; }>) {
...
tracks.forEach((track, index) => {
...
// Check to see if artist exists, if not create, if so, add this track
let artist = draft.artists[artistId];
if (!artist) {
console.log("creating artist", track.artist);
draft.artists[artistId] = produce({
name: track.artist,
albums: [],
id: artistId,
tracks: [track.id]
}, (artistDraft): IArtist => {
console.log("producing the artist");
return artistDraft;
});
} else {
console.log("updating artist");
draft.artists[artistId].tracks.push(track.id);
}
这对于每个艺术家的第一首曲目来说都很好。然而,当immer创建每个新的艺术家对象并将其添加到状态时,它会使每个对象的轨迹阵列不可扩展。
Uncaught TypeError: Cannot add property 1, object is not extensible
从抛出
draft.artists[artistId].tracks.push(track.id);
我推测这是因为我没有正确创建嵌套的艺术家草稿,或者redux不支持这种行为。这就是为什么我从使用纯对象转换为嵌套的immer draft——但这似乎不起作用。
我也试过。。。
draft.artists[artistId].tracks = [...draft.artists[artistId].tracks, track.id];
但是在这种情况下tracks
属性是只读的。
如何在没有错误的情况下实现此功能?
我终于找到了这个。我的减速器写得很正确,但在更高的堆栈中,我意外地从redux-immer
而不是redux
本身导入了combineReducers
。redux-immer
是一个用于将immer集成到redux中的库。
这导致我的商店通过immer运行了两次(一次通过createSlice
,一次通过combineReducers
(,这导致。。。想不到的行为,包括immer锁定自身,导致上述对象被锁定。
毫无疑问,这是一种有趣的方式来度过过去的两周。