v19.2Latest

Actualizar arrays en el estado

Los arrays son mutables en JavaScript, pero debes tratarlos como inmutables cuando los almacenas en el estado. Al igual que con los objetos, cuando quieres actualizar un array almacenado en el estado, necesitas crear uno nuevo (o hacer una copia de uno existente) y luego establecer el estado para usar el nuevo array.

Aprenderás
  • Cómo agregar, eliminar o cambiar elementos en un array en el estado de React
  • Cómo actualizar un objeto dentro de un array
  • Cómo hacer que la copia de arrays sea menos repetitiva con Immer

Actualizar arrays sin mutación

En JavaScript, los arrays son simplemente otro tipo de objeto.Al igual que con los objetos,debes tratar los arrays en el estado de React como de solo lectura.Esto significa que no debes reasignar elementos dentro de un array comoarr[0] = 'bird', y tampoco debes usar métodos que muten el array, comopush() y pop().

En su lugar, cada vez que quieras actualizar un array, deberás pasar un arraynuevoa tu función de establecimiento de estado. Para hacerlo, puedes crear un nuevo array a partir del array original en tu estado llamando a sus métodos no mutantes comofilter() y map(). Luego puedes establecer tu estado al nuevo array resultante.

Aquí hay una tabla de referencia de operaciones comunes con arrays. Al tratar con arrays dentro del estado de React, deberás evitar los métodos de la columna izquierda y preferir los métodos de la columna derecha:

evitar (muta el array)preferir (devuelve un nuevo array)
agregarpush,unshiftconcat,[...arr]sintaxis de propagación (ejemplo)
eliminarpop,shift,splicefilter,slice(ejemplo)
reemplazarsplice,arr[i] = ...asignaciónmap(ejemplo)
ordenarreverse,sortcopiar el array primero (ejemplo)

Alternativamente, puedesusar Immerque te permite usar métodos de ambas columnas.

Peligro

Desafortunadamente,slice y splicetienen nombres similares pero son muy diferentes:

  • slicete permite copiar un array o una parte de él.
  • splicemutael array (para insertar o eliminar elementos).

En React, usarásslice(¡sinp!) mucho más a menudo porque no quieres mutar objetos o arrays en el estado.Actualizar objetosexplica qué es la mutación y por qué no se recomienda para el estado.

Agregar a un array

push()mutará un array, lo cual no quieres:

En su lugar, crea unnuevoarray que contenga los elementos existentesyun nuevo elemento al final. Hay varias formas de hacer esto, pero la más fácil es usar la sintaxis de...propagación de arrays:

Ahora funciona correctamente:

La sintaxis de propagación de arrays también te permite anteponer un elemento colocándoloantes del ...artists original:

De esta manera, la propagación puede hacer el trabajo tanto depush()al agregar al final de un array como deunshift()al agregar al principio de un array. ¡Pruébalo en el sandbox de arriba!

Eliminar de un array

La forma más fácil de eliminar un elemento de un array esfiltrarlo. En otras palabras, producirás un nuevo array que no contendrá ese elemento. Para hacer esto, usa el métodofilter, por ejemplo:

Haz clic en el botón “Delete” varias veces y observa su controlador de clics.

Aquí,artists.filter(a => a.id !== artist.id)significa “crear un array que consista en aquellosartistscuyos IDs son diferentes deartist.id”. En otras palabras, el botón “Delete” de cada artista filtraráa eseartista fuera del array, y luego solicitará una nueva renderización con el array resultante. Ten en cuenta quefilterno modifica el array original.

Transformar un array

Si quieres cambiar algunos o todos los elementos del array, puedes usarmap()para crear un arraynuevo. La función que pasarás amappuede decidir qué hacer con cada elemento, basándose en sus datos o su índice (o ambos).

En este ejemplo, un array contiene las coordenadas de dos círculos y un cuadrado. Cuando presionas el botón, solo mueve los círculos hacia abajo 50 píxeles. Lo hace produciendo un nuevo array de datos usandomap():

Reemplazar elementos en un array

Es particularmente común querer reemplazar uno o más elementos en un array. Asignaciones comoarr[0] = 'bird'están mutando el array original, por lo que en su lugar también querrás usarmappara esto.

Para reemplazar un elemento, crea un nuevo array conmap. Dentro de tu llamada amap, recibirás el índice del elemento como segundo argumento. Úsalo para decidir si devolver el elemento original (el primer argumento) o algo más:

Insertar en un array

A veces, es posible que desees insertar un elemento en una posición específica que no sea ni al principio ni al final. Para hacer esto, puedes usar la sintaxis de propagación de arrays...junto con el métodoslice(). El métodoslice()te permite cortar un "trozo" del array. Para insertar un elemento, crearás un array que propague el trozoantesdel punto de inserción, luego el nuevo elemento, y luego el resto del array original.

En este ejemplo, el botón Insertar siempre inserta en el índice1:

Realizar otros cambios en un array

Hay algunas cosas que no puedes hacer solo con la sintaxis de propagación y métodos no mutantes comomap() y filter(). Por ejemplo, es posible que desees invertir u ordenar un array. Los métodos de JavaScriptreverse() y sort()mutan el array original, por lo que no puedes usarlos directamente.

Sin embargo, puedes copiar el array primero y luego hacer cambios en él.

Por ejemplo:

Aquí, usas la sintaxis de propagación[...list]para crear primero una copia del array original. Ahora que tienes una copia, puedes usar métodos mutantes comonextList.reverse() o nextList.sort(), o incluso asignar elementos individuales connextList[0] = "something".

Sin embargo,incluso si copias un array, no puedes mutar elementos existentesdentrode él directamente.Esto se debe a que la copia es superficial: el nuevo array contendrá los mismos elementos que el original. Por lo tanto, si modificas un objeto dentro del array copiado, estás mutando el estado existente. Por ejemplo, un código como este es un problema.

AunquenextList y listson dos arrays diferentes,nextList[0] y list[0]apuntan al mismo objeto.Así que al cambiarnextList[0].seen, también estás cambiandolist[0].seen. ¡Esto es una mutación de estado, que debes evitar! Puedes resolver este problema de manera similar aactualizar objetos JavaScript anidados—copiando los elementos individuales que deseas cambiar en lugar de mutarlos. Así es cómo.

Actualizar objetos dentro de arrays

Los objetos no estánrealmente"dentro" de los arrays. Pueden parecer estar "dentro" en el código, pero cada objeto en un array es un valor separado, al que el array "apunta". Por eso debes tener cuidado al cambiar campos anidados comolist[0]. ¡La lista de obras de arte de otra persona puede apuntar al mismo elemento del array!

Al actualizar un estado anidado, necesitas crear copias desde el punto donde deseas actualizar, y hacia arriba hasta el nivel superior.Veamos cómo funciona esto.

En este ejemplo, dos listas de obras de arte separadas tienen el mismo estado inicial. Se supone que están aisladas, pero debido a una mutación, su estado se comparte accidentalmente, y marcar una casilla en una lista afecta a la otra lista:

El problema está en código como este:

Aunque el arraymyNextListen sí es nuevo,los elementos en síson los mismos que en el array originalmyList. Por lo tanto, cambiarartwork.seencambia el elemento de arteoriginal. Ese elemento de arte también está enyourList, lo que provoca el error. Errores como este pueden ser difíciles de razonar, pero afortunadamente desaparecen si evitas mutar el estado.

Puedes usarmappara sustituir un elemento antiguo por su versión actualizada sin mutación.

Aquí,...es la sintaxis de propagación de objetos utilizada paracrear una copia de un objeto.

Con este enfoque, ninguno de los elementos de estado existentes se está mutando, y el error se soluciona:

En general,solo debes mutar objetos que acabas de crear.Si estuvieras insertando una obra de artenueva, podrías mutarla, pero si estás tratando con algo que ya está en el estado, necesitas hacer una copia.

Escribe lógica de actualización concisa con Immer

Actualizar arrays anidados sin mutación puede volverse un poco repetitivo.Al igual que con los objetos:

  • Generalmente, no deberías necesitar actualizar el estado más de un par de niveles de profundidad. Si tus objetos de estado son muy profundos, quizás quierasreestructurarlos de manera diferentepara que sean planos.
  • Si no quieres cambiar la estructura de tu estado, quizás prefieras usarImmer, que te permite escribir usando la sintaxis conveniente pero mutante y se encarga de producir las copias por ti.

Aquí está el ejemplo de la Lista de Arte para Ver reescrito con Immer:

Observa cómo con Immer,mutaciones comoartwork.seen = nextSeenahora están permitidas:

Esto se debe a que no estás mutando el estadooriginal, sino que estás mutando un objeto especialdraftproporcionado por Immer. De manera similar, puedes aplicar métodos mutantes comopush() y pop()al contenido deldraft.

Internamente, Immer siempre construye el siguiente estado desde cero según los cambios que hayas realizado en eldraft. Esto mantiene tus controladores de eventos muy concisos sin mutar nunca el estado.

Recapitulación

  • Puedes colocar arrays en el estado, pero no puedes cambiarlos.
  • En lugar de mutar un array, crea una versiónnuevadel mismo y actualiza el estado con ella.
  • Puedes usar la sintaxis de propagación de arrays[...arr, newItem]para crear arrays con nuevos elementos.
  • Puedes usarfilter() y map()para crear nuevos arrays con elementos filtrados o transformados.
  • Puedes usar Immer para mantener tu código conciso.

Try out some challenges

Challenge 1 of 4:Update an item in the shopping cart #

Fill in the handleIncreaseClick logic so that pressing ”+” increases the corresponding number: