es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Immer – Mutar objeto anidado recién creado.

Estoy utilizando immer (a través de createSlice en redux-toolkit) para gestionar el estado en una aplicación de redux. He escrito un reductor que recibe una carga útil de pistas de música y las agrega a la biblioteca de usuarios. En parte, este reductor también debe crear entradas de artistas para cada una de las pistas.

createTracks(draft, action: PayloadAction<{ tracks: Array<itrack> | ITrack; }>) {
  ...
  tracks.forEach((track, index) => {
    ...
      // Comprueba si el artista existe, si no, crea uno nuevo, si sí, agrega esta pista
      let artist = draft.artists[artistId];
      if (!artist) {
        console.log("creando artista", track.artist);
        draft.artists[artistId] = produce({
          name: track.artist,
          albums: [],
          id: artistId,
          tracks: [track.id]
        }, (artistDraft): IArtist => {
          console.log("produciendo el artista");
          return artistDraft;
        });
      } else {
        console.log("actualizando artista");
        draft.artists[artistId].tracks.push(track.id);
      }

Esto funciona bien para las primeras pistas de cada artista. Sin embargo, cuando immer crea cada nuevo objeto de artista y lo agrega al estado, hace que el array de pistas para cada objeto no sea extensible.

Uncaught TypeError: No se puede agregar la propiedad 1, el objeto no es extensible

se lanza desde

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

Presumí que esto se debe a que o no estoy creando correctamente el borrador anidado del artista o redux no admite este comportamiento. Es por eso que cambié de usar un objeto puro a un borrador anidado de immer, pero esto no pareció funcionar.

También he intentado…

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

… pero en este caso, la propiedad tracks es de solo lectura.

¿Cómo puedo implementar esto sin el error?

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    El problema aquí es que el array tracks de cada objeto de artista no es extensible una vez que ha sido creado. Para abordar este problema, puedes usar nuevamente la función immer.produce para crear un nuevo borrador del objeto de artista, lo cual te permite modificar el array tracks manteniendo inalterado el objeto original y sus propiedades.

    Aquí tienes una versión actualizada del código del reductor:

    createTracks(draft, action: PayloadAction<{ tracks: Array<itrack> | ITrack }>) {
      const { tracks } = action.payload;
    
      tracks.forEach((track, index) => {
        const artistId = getArtistId(track.artist);
    
        if (!draft.artists[artistId]) {
          draft.artists[artistId] = {
            name: track.artist,
            albums: [],
            id: artistId,
            tracks: [track.id]
          };
        } else {
          draft.artists[artistId] = produce(draft.artists[artistId], (artistDraft) => {
            artistDraft.tracks.push(track.id);
          });
        }
      });
    }
    

    En este código actualizado, creamos un nuevo borrador del objeto de artista existente usando immer.produce y actualizamos su array tracks agregando el nuevo track.id. De esta manera, podemos modificar el array tracks sin hacerlo no extensible.

    Espero que esto ayude. Avísame si tienes alguna pregunta adicional.

Comments are closed.