简体   繁体   中英

Immer - Mutate Newly Created Nested Object

I'm using immer (via createSlice in redux-toolkit ) to manage state in a redux application. I've written a reducer that takes a payload of music tracks and adds them to the users library. In part, this reducer must also create artist entries for each of the tracks.

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);
      }

This works fine for the first tracks from each artist. However, when immer creates each new artist object and adds it to the state, it makes the track array for each object not extensible.

Uncaught TypeError: Cannot add property 1, object is not extensible
      

is thrown from

draft.artists[artistId].tracks.push(track.id);

I've presumed that this is because I'm either not creating the the nested artist draft correctly or redux doesn't support this behavior. That's why I shifted from using a pure object to a nested immer draft - but this didn't seem to work.

I have also tried...

draft.artists[artistId].tracks = [...draft.artists[artistId].tracks, track.id];

... but in this case, the tracks property is read only.

How can I implement this without the error?

I finally traced this down. My reducers were written correctly, but higher up the stack I was accidentally importing combineReducers from redux-immer instead of redux itself. redux-immer is a library for integrating immer into redux.

This resulted in running my store through immer twice (once via createSlice and once via combineReducers ), which caused... unexpected... behaviors, including immer locking itself, resulting in the objects described above getting locked.

It's been a fun way to spend the last two weeks, for sure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM