v19.2Latest

Atualizando Arrays no Estado

Arrays são mutáveis em JavaScript, mas você deve tratá-los como imutáveis quando os armazena no estado. Assim como com objetos, quando você deseja atualizar um array armazenado no estado, precisa criar um novo (ou fazer uma cópia de um existente) e, em seguida, definir o estado para usar o novo array.

Você aprenderá
  • Como adicionar, remover ou alterar itens em um array no estado do React
  • Como atualizar um objeto dentro de um array
  • Como tornar a cópia de arrays menos repetitiva com Immer

Atualizando arrays sem mutação

Em JavaScript, arrays são apenas outro tipo de objeto.Como com objetos,você deve tratar arrays no estado do React como somente leitura.Isso significa que você não deve reatribuir itens dentro de um array comoarr[0] = 'bird', e também não deve usar métodos que mutam o array, comopush() e pop().

Em vez disso, sempre que você quiser atualizar um array, deverá passar um arraynovopara sua função de configuração de estado. Para fazer isso, você pode criar um novo array a partir do array original em seu estado chamando seus métodos não mutantes, comofilter() e map(). Em seguida, você pode definir seu estado para o novo array resultante.

Aqui está uma tabela de referência de operações comuns em arrays. Ao lidar com arrays dentro do estado do React, você precisará evitar os métodos da coluna esquerda e preferir os métodos da coluna direita:

evitar (muta o array)preferir (retorna um novo array)
adiçãopush,unshiftconcat,[...arr]sintaxe de espalhamento (exemplo)
remoçãopop,shift,splicefilter,slice(exemplo)
substituiçãosplice,arr[i] = ...atribuiçãomap(exemplo)
ordenaçãoreverse,sortcopie o array primeiro (exemplo)

Alternativamente, você podeusar Immerque permite usar métodos de ambas as colunas.

Armadilha

Infelizmente,slice e splicetêm nomes semelhantes, mas são muito diferentes:

  • slicepermite copiar um array ou uma parte dele.
  • splicemutao array (para inserir ou excluir itens).

No React, você usaráslice(semp!) com muito mais frequência porque você não quer mutar objetos ou arrays no estado.Atualizando Objetosexplica o que é mutação e por que não é recomendada para o estado.

Adicionando a um array

push()irá mutar um array, o que você não quer:

Em vez disso, crie umnovoarray que contenha os itens existenteseum novo item no final. Existem várias maneiras de fazer isso, mas a mais fácil é usar a sintaxe de...espalhamento de array:

Agora funciona corretamente:

A sintaxe de espalhamento de array também permite adicionar um item no início, colocando-oantesdo original...artists:

Dessa forma, o espalhamento pode fazer o trabalho tanto dopush(), adicionando ao final de um array, quanto dounshift(), adicionando ao início de um array. Experimente no sandbox acima!

Removendo de um array

A maneira mais fácil de remover um item de um array éfiltrá-lo. Em outras palavras, você produzirá um novo array que não conterá esse item. Para fazer isso, use o métodofilter, por exemplo:

Clique no botão “Delete” algumas vezes e observe seu manipulador de clique.

Aqui,artists.filter(a => a.id !== artist.id)significa “crie um array que consiste naquelesartistscujos IDs são diferentes deartist.id”. Em outras palavras, o botão “Delete” de cada artista filtraráaqueleartista para fora do array e, em seguida, solicitará uma nova renderização com o array resultante. Observe quefilternão modifica o array original.

Transformando um array

Se você quiser alterar alguns ou todos os itens do array, pode usarmap()para criar umnovoarray. A função que você passará paramappode decidir o que fazer com cada item, com base em seus dados ou em seu índice (ou ambos).

Neste exemplo, um array contém as coordenadas de dois círculos e um quadrado. Quando você pressiona o botão, ele move apenas os círculos 50 pixels para baixo. Ele faz isso produzindo um novo array de dados usandomap():

Substituindo itens em um array

É particularmente comum querer substituir um ou mais itens em um array. Atribuições comoarr[0] = 'bird'estão mutando o array original, então, em vez disso, você também vai querer usarmappara isso.

Para substituir um item, crie um novo array commap. Dentro da sua chamadamap, você receberá o índice do item como segundo argumento. Use-o para decidir se retorna o item original (o primeiro argumento) ou outra coisa:

Inserindo em um array

Às vezes, você pode querer inserir um item em uma posição específica que não seja nem no início nem no final. Para fazer isso, você pode usar a sintaxe de espalhamento de array...junto com o métodoslice(). O métodoslice()permite que você corte uma "fatia" do array. Para inserir um item, você criará um array que espalha a fatiaantesdo ponto de inserção, depois o novo item e, em seguida, o restante do array original.

Neste exemplo, o botão Inserir sempre insere no índice1:

Fazendo outras alterações em um array

Há algumas coisas que você não pode fazer apenas com a sintaxe de espalhamento e métodos não mutantes comomap() e filter(). Por exemplo, você pode querer reverter ou ordenar um array. Os métodos JavaScriptreverse() e sort()alteram o array original, então você não pode usá-los diretamente.

No entanto, você pode copiar o array primeiro e depois fazer alterações nele.

Por exemplo:

Aqui, você usa a sintaxe de espalhamento[...list]para criar uma cópia do array original primeiro. Agora que você tem uma cópia, pode usar métodos mutantes comonextList.reverse()ounextList.sort(), ou até mesmo atribuir itens individuais comnextList[0] = "something".

No entanto,mesmo que você copie um array, não pode alterar itens existentesdentrodele diretamente.Isso ocorre porque a cópia é superficial — o novo array conterá os mesmos itens do original. Portanto, se você modificar um objeto dentro do array copiado, estará alterando o estado existente. Por exemplo, um código como este é um problema.

EmboranextList e listsejam dois arrays diferentes,nextList[0] e list[0]apontam para o mesmo objeto.Portanto, ao alterarnextList[0].seen, você também está alterandolist[0].seen. Isso é uma mutação de estado, que você deve evitar! Você pode resolver esse problema de maneira semelhante àatualização de objetos JavaScript aninhados—copiando os itens individuais que você deseja alterar em vez de mutá-los. Veja como.

Atualizando objetos dentro de arrays

Os objetos não estãorealmentelocalizados "dentro" dos arrays. Eles podem parecer estar "dentro" no código, mas cada objeto em um array é um valor separado, para o qual o array "aponta". É por isso que você precisa ter cuidado ao alterar campos aninhados comolist[0]. A lista de obras de arte de outra pessoa pode apontar para o mesmo elemento do array!

Ao atualizar um estado aninhado, você precisa criar cópias a partir do ponto onde deseja atualizar, e por todo o caminho até o nível superior.Vamos ver como isso funciona.

Neste exemplo, duas listas de obras de arte separadas têm o mesmo estado inicial. Elas deveriam ser isoladas, mas devido a uma mutação, seu estado é compartilhado acidentalmente, e marcar uma caixa em uma lista afeta a outra lista:

O problema está em um código como este:

Embora o próprio arraymyNextListseja novo,os itens em sisão os mesmos do array originalmyList. Portanto, alterarartwork.seenaltera o item de arteoriginal. Esse item de arte também está emyourList, o que causa o bug. Bugs como esse podem ser difíceis de pensar, mas felizmente eles desaparecem se você evitar a mutação do estado.

Você pode usarmappara substituir um item antigo por sua versão atualizada sem mutação.

Aqui,...é a sintaxe de espalhamento de objeto usada paracriar uma cópia de um objeto.

Com essa abordagem, nenhum dos itens de estado existentes está sendo mutado, e o bug é corrigido:

Em geral,você só deve mutar objetos que acabou de criar.Se você estivesse inserindo uma obra de artenova, você poderia mutá-la, mas se estiver lidando com algo que já está no estado, você precisa fazer uma cópia.

Escreva lógica de atualização concisa com Immer

Atualizar arrays aninhados sem mutação pode ficar um pouco repetitivo.Assim como com objetos:

  • Geralmente, você não precisa atualizar o estado mais do que alguns níveis de profundidade. Se seus objetos de estado forem muito profundos, talvez você queirareestruturá-los de forma diferentepara que fiquem planos.
  • Se você não quiser alterar a estrutura do seu estado, pode preferir usarImmer, que permite escrever usando a sintaxe conveniente, mas mutante, e cuida de produzir as cópias para você.

Aqui está o exemplo da Lista de Desejos de Arte reescrito com Immer:

Observe como, com o Immer,mutações comoartwork.seen = nextSeenagora são aceitáveis:

Isso ocorre porque você não está mutando o estadooriginal, mas sim um objeto especialdraftfornecido pelo Immer. Da mesma forma, você pode aplicar métodos mutantes comopush() e pop()ao conteúdo dodraft.

Nos bastidores, o Immer sempre constrói o próximo estado do zero de acordo com as alterações que você fez nodraft. Isso mantém seus manipuladores de eventos muito concisos sem nunca mutar o estado.

Recapitulação

  • Você pode colocar arrays no estado, mas não pode alterá-los.
  • Em vez de mutar um array, crie uma versãonovadele e atualize o estado para ela.
  • Você pode usar a sintaxe de espalhamento de array[...arr, newItem]para criar arrays com novos itens.
  • Você pode usarfilter() e map()para criar novos arrays com itens filtrados ou transformados.
  • Você pode usar o Immer para manter seu 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: