v19.2Latest

Enfileirando uma Série de Atualizações de Estado

Definir uma variável de estado enfileira outra renderização. Mas às vezes você pode querer realizar várias operações no valor antes de enfileirar a próxima renderização. Para fazer isso, ajuda entender como o React agrupa (batches) as atualizações de estado.

Você aprenderá
  • O que é “agrupamento” (batching) e como o React o usa para processar múltiplas atualizações de estado
  • Como aplicar várias atualizações à mesma variável de estado em sequência

O React agrupa as atualizações de estado

Você pode esperar que clicar no botão “+3” incremente o contador três vezes porque ele chamasetNumber(number + 1)três vezes:

No entanto, como você pode se lembrar da seção anterior,os valores de estado de cada renderização são fixos, então o valor denumberdentro do manipulador de eventos da primeira renderização é sempre0, não importa quantas vezes você chamesetNumber(1):

Mas há outro fator em jogo aqui.O React espera até quetodoo código nos manipuladores de eventos tenha sido executado antes de processar suas atualizações de estado.É por isso que a re-renderização só acontecedepoisde todas essas chamadassetNumber().

Isso pode lembrá-lo de um garçom anotando um pedido em um restaurante. Um garçom não corre para a cozinha ao ouvir seu primeiro prato! Em vez disso, ele deixa você terminar seu pedido, permite que você faça alterações nele e até mesmo anota pedidos de outras pessoas na mesa.

Um cursor elegante em um restaurante faz um pedido várias vezes com o React, atuando como o garçom. Depois que ela chama setState() várias vezes, o garçom anota o último que ela solicitou como seu pedido final.

Ilustrado porRachel Lee Nabors

Isso permite que você atualize múltiplas variáveis de estado—mesmo de múltiplos componentes—sem acionar muitasre-renderizações.Mas isso também significa que a interface do usuário não será atualizada atédepoisdo seu manipulador de eventos e de qualquer código nele ter sido concluído. Este comportamento, também conhecido comoagrupamento (batching),faz seu aplicativo React rodar muito mais rápido. Ele também evita lidar com renderizações confusas “pela metade”, onde apenas algumas das variáveis foram atualizadas.

O React não agrupa entremúltiploseventos intencionais como cliques—cada clique é tratado separadamente. Fique tranquilo que o React só faz agrupamento quando é geralmente seguro fazê-lo. Isso garante que, por exemplo, se o primeiro clique de botão desabilitar um formulário, o segundo clique não o enviaria novamente.

Atualizando o mesmo estado várias vezes antes da próxima renderização

É um caso de uso incomum, mas se você quiser atualizar a mesma variável de estado várias vezes antes da próxima renderização, em vez de passar opróximo valor de estadocomosetNumber(number + 1), você pode passar umafunçãoque calcula o próximo estado com base no anterior na fila, comosetNumber(n => n + 1). É uma forma de dizer ao React para “fazer algo com o valor do estado” em vez de apenas substituí-lo.

Tente incrementar o contador agora:

Aqui,n => n + 1é chamada defunção de atualização (updater function).Quando você a passa para um definidor de estado:

  1. O React enfileira esta função para ser processada depois que todo o outro código no manipulador de eventos for executado.
  2. Durante a próxima renderização, o React percorre a fila e fornece o estado final atualizado.

Veja como o React processa essas linhas de código enquanto executa o manipulador de eventos:

  1. setNumber(n => n + 1):n => n + 1é uma função. O React a adiciona a uma fila.
  2. setNumber(n => n + 1):n => n + 1é uma função. O React a adiciona a uma fila.
  3. setNumber(n => n + 1):n => n + 1é uma função. O React a adiciona a uma fila.

Quando você chamauseStatedurante a próxima renderização, o React percorre a fila. O estado anterior denumber era 0, então é isso que o React passa para a primeira função de atualização como argumenton. Em seguida, o React pega o valor de retorno da sua função de atualização anterior e o passa para a próxima atualização comon, e assim por diante:

atualização na filanretorna
n => n + 100 + 1 = 1
n => n + 111 + 1 = 2
n => n + 122 + 1 = 3

O React armazena3como resultado final e o retorna deuseState.

É por isso que clicar em “+3” no exemplo acima incrementa corretamente o valor em 3.

O que acontece se você atualizar o estado após substituí-lo

E este manipulador de eventos? Qual você acha que será o valor denumberna próxima renderização?

Aqui está o que este manipulador de eventos diz ao React para fazer:

  1. setNumber(number + 5):number é 0, entãosetNumber(0 + 5). O React adiciona“substituir por5à sua fila.
  2. setNumber(n => n + 1):n => n + 1é uma função de atualização. O React adicionaessa funçãoà sua fila.

Durante a próxima renderização, o React percorre a fila de estado:

atualização na filanretorna
”substituir por50(não utilizado)5
n => n + 155 + 1 = 6

O React armazena6como o resultado final e o retorna douseState.

Observação

Você pode ter notado quesetState(5)funciona na verdade comosetState(n => 5), masnnão é utilizado!

O que acontece se você substituir o estado após atualizá-lo

Vamos tentar mais um exemplo. Qual você acha que será o valor denumberna próxima renderização?

Veja como o React processa essas linhas de código ao executar este manipulador de eventos:

  1. setNumber(number + 5):number é 0, entãosetNumber(0 + 5). O React adiciona“substituir por5à sua fila.
  2. setNumber(n => n + 1):n => n + 1é uma função de atualização. O React adicionaessa funçãoà sua fila.
  3. setNumber(42): O React adiciona“substituir por42à sua fila.

Durante a próxima renderização, o React percorre a fila de estado:

atualização na filanretorna
”substituir por50(não usado)5
n => n + 155 + 1 = 6
”substituir por426(não usado)42

Em seguida, o React armazena42como o resultado final e o retorna douseState.

Para resumir, eis como você pode pensar sobre o que está passando para a função de definição de estadosetNumber:

  • Uma função de atualização(ex:n => n + 1) é adicionada à fila.
  • Qualquer outro valor(ex: o número5) adiciona “substituir por5” à fila, ignorando o que já está na fila.

Após o manipulador de eventos ser concluído, o React acionará uma nova renderização. Durante a nova renderização, o React processará a fila. As funções de atualização são executadas durante a renderização, portanto,as funções de atualização devem serpurase apenasretornaro resultado. Não tente definir o estado de dentro delas ou executar outros efeitos colaterais. No Modo Estrito, o React executará cada função de atualização duas vezes (mas descartará o segundo resultado) para ajudá-lo a encontrar erros.

Convenções de nomenclatura

É comum nomear o argumento da função de atualização pelas primeiras letras da variável de estado correspondente:

Se você preferir um código mais verboso, outra convenção comum é repetir o nome completo da variável de estado, comosetEnabled(enabled => !enabled), ou usar um prefixo comosetEnabled(prevEnabled => !prevEnabled).

Recapitulação

  • Definir o estado não altera a variável na renderização existente, mas solicita uma nova renderização.
  • O React processa as atualizações de estado após os manipuladores de eventos terminarem de executar. Isso é chamado de agrupamento (batching).
  • Para atualizar algum estado várias vezes em um evento, você pode usar a função de atualizaçãosetNumber(n => n + 1).

Experimente alguns desafios

Challenge 1 of 2:Corrija um contador de solicitações #

Você está trabalhando em um aplicativo de mercado de arte que permite ao usuário enviar vários pedidos de um item de arte ao mesmo tempo. Cada vez que o usuário pressiona o botão “Comprar”, o contador “Pendente” deve aumentar em um. Após três segundos, o contador “Pendente” deve diminuir e o contador “Concluído” deve aumentar.

No entanto, o contador “Pendente” não se comporta conforme o esperado. Quando você pressiona “Comprar”, ele diminui para -1 (o que não deveria ser possível!). E se você clicar rapidamente duas vezes, ambos os contadores parecem se comportar de forma imprevisível.

Por que isso acontece? Corrija ambos os contadores.