v19.2Latest

Reagindo a Entradas com Estado

O React fornece uma maneira declarativa de manipular a interface do usuário. Em vez de manipular diretamente partes individuais da interface, você descreve os diferentes estados em que seu componente pode estar e alterna entre eles em resposta à entrada do usuário. Isso é semelhante à forma como os designers pensam sobre a interface do usuário.

Você aprenderá
  • Como a programação declarativa de interface do usuário difere da programação imperativa de interface do usuário
  • Como enumerar os diferentes estados visuais em que seu componente pode estar
  • Como acionar as mudanças entre os diferentes estados visuais a partir do código

Como a interface declarativa se compara à imperativa

Ao projetar interações de interface do usuário, você provavelmente pensa em como a interfacemudaem resposta às ações do usuário. Considere um formulário que permite ao usuário enviar uma resposta:

  • Quando você digita algo no formulário, o botão "Enviar"se torna habilitado.
  • Quando você pressiona "Enviar", tanto o formulário quanto o botãose tornam desabilitados,e um indicador de carregamentoaparece.
  • Se a requisição de rede for bem-sucedida, o formuláriofica oculto,e a mensagem "Obrigado"aparece.
  • Se a requisição de rede falhar, uma mensagem de erroaparece,e o formuláriose torna habilitadonovamente.

Naprogramação imperativa,o acima corresponde diretamente à forma como você implementa a interação. Você tem que escrever as instruções exatas para manipular a interface do usuário dependendo do que acabou de acontecer. Aqui está outra maneira de pensar sobre isso: imagine estar ao lado de alguém em um carro e dizer a eles, curva por curva, para onde ir.

Em um carro dirigido por uma pessoa com aparência ansiosa representando o JavaScript, um passageiro ordena ao motorista que execute uma sequência complicada de navegações curva por curva.

Ilustrado porRachel Lee Nabors

Eles não sabem para onde você quer ir, eles apenas seguem seus comandos. (E se você errar as direções, você acaba no lugar errado!) É chamado deimperativoporque você tem que "comandar" cada elemento, do indicador de carregamento ao botão, dizendo ao computadorcomoatualizar a interface do usuário.

Neste exemplo de programação imperativa de interface do usuário, o formulário é construídosemo React. Ele usa apenas oDOMdo navegador:

Manipular a UI de forma imperativa funciona bem o suficiente para exemplos isolados, mas fica exponencialmente mais difícil de gerenciar em sistemas mais complexos. Imagine atualizar uma página cheia de formulários diferentes como este. Adicionar um novo elemento de UI ou uma nova interação exigiria verificar cuidadosamente todo o código existente para garantir que você não introduziu um bug (por exemplo, esquecer de mostrar ou ocultar algo).

O React foi construído para resolver esse problema.

No React, você não manipula a UI diretamente — ou seja, você não habilita, desabilita, mostra ou oculta componentes diretamente. Em vez disso, vocêdeclara o que deseja mostrar,e o React descobre como atualizar a UI. Pense em entrar em um táxi e dizer ao motorista para onde você quer ir, em vez de dizer exatamente onde virar. É trabalho do motorista levá-lo até lá, e ele pode até conhecer alguns atalhos que você não considerou!

Em um carro dirigido pelo React, um passageiro pede para ser levado a um local específico no mapa. O React descobre como fazer isso.

Ilustrado porRachel Lee Nabors

Pensando sobre a UI de forma declarativa

Você viu como implementar um formulário de forma imperativa acima. Para entender melhor como pensar em React, você percorrerá a reimplementação desta UI em React abaixo:

  1. Identifiqueos diferentes estados visuais do seu componente
  2. Determineo que aciona essas mudanças de estado
  3. Representeo estado na memória usandouseState
  4. Removaquaisquer variáveis de estado não essenciais
  5. Conecteos manipuladores de eventos para definir o estado

Passo 1: Identifique os diferentes estados visuais do seu componente

Em ciência da computação, você pode ouvir falar sobre uma“máquina de estados”estar em um de vários “estados”. Se você trabalha com um designer, pode ter visto maquetes para diferentes “estados visuais”. O React está na interseção entre design e ciência da computação, então ambas as ideias são fontes de inspiração.

Primeiro, você precisa visualizar todos os diferentes “estados” da interface do usuário que o usuário pode ver:

  • Vazio: O formulário tem um botão “Enviar” desabilitado.
  • Digitando: O formulário tem um botão “Enviar” habilitado.
  • Enviando: O formulário está completamente desabilitado. Um spinner é mostrado.
  • Sucesso: A mensagem “Obrigado” é mostrada no lugar do formulário.
  • Erro: O mesmo estado de Digitando, mas com uma mensagem de erro extra.

Assim como um designer, você vai querer “maquetar” ou criar “maquetes” para os diferentes estados antes de adicionar lógica. Por exemplo, aqui está uma maquete apenas para a parte visual do formulário. Esta maquete é controlada por uma prop chamadastatuscom um valor padrão de'empty':

Você pode chamar essa prop como quiser, a nomenclatura não é importante. Tente editarstatus = 'empty'parastatus = 'success'para ver a mensagem de sucesso aparecer. A maquetagem permite que você itere rapidamente na interface do usuário antes de conectar qualquer lógica. Aqui está um protótipo mais completo do mesmo componente, ainda “controlado” pela propstatus:

Passo 2: Determine o que aciona essas mudanças de estado

Você pode acionar atualizações de estado em resposta a dois tipos de entradas:

  • Entradas humanas,como clicar em um botão, digitar em um campo, navegar por um link.
  • Entradas do computador,como a chegada de uma resposta de rede, a conclusão de um tempo limite, o carregamento de uma imagem.
Um dedo.Uns e zeros.

Ilustrado porRachel Lee Nabors

Em ambos os casos

  • Alterar a entrada de texto(humano) deve alterná-lo do estadoVaziopara o estadoDigitandoou vice-versa, dependendo se a caixa de texto está vazia ou não.
  • Clicar no botão Enviar(humano) deve alterná-lo para o estadoEnviando.
  • Resposta de rede bem-sucedida(computador) deve alterná-lo para o estadoSucesso.
  • Resposta de rede com falha(computador) deve alterná-lo para o estadoErrocom a mensagem de erro correspondente.
Observação

Observe que entradas humanas frequentemente exigemmanipuladores de eventos!

Para ajudar a visualizar esse fluxo, tente desenhar cada estado no papel como um círculo rotulado e cada mudança entre dois estados como uma seta. Você pode esboçar muitos fluxos dessa forma e corrigir bugs muito antes da implementação.

Diagrama de fluxo movendo-se da esquerda para a direita com 5 nós. O primeiro nó rotulado 'vazio' tem uma aresta rotulada 'começar a digitar' conectada a um nó rotulado 'digitando'. Esse nó tem uma aresta rotulada 'pressionar enviar' conectada a um nó rotulado 'enviando', que tem duas arestas. A aresta esquerda é rotulada 'erro de rede' conectando a um nó rotulado 'erro'. A aresta direita é rotulada 'sucesso de rede' conectando a um nó rotulado 'sucesso'.Diagrama de fluxo movendo-se da esquerda para a direita com 5 nós. O primeiro nó rotulado 'vazio' tem uma aresta rotulada 'começar a digitar' conectada a um nó rotulado 'digitando'. Esse nó tem uma aresta rotulada 'pressionar enviar' conectada a um nó rotulado 'enviando', que tem duas arestas. A aresta esquerda é rotulada 'erro de rede' conectando a um nó rotulado 'erro'. A aresta direita é rotulada 'sucesso de rede' conectando a um nó rotulado 'sucesso'.

Estados do formulário

Passo 3: Representar o estado na memória comuseState

Em seguida, você precisará representar os estados visuais do seu componente na memória comuseState.A simplicidade é fundamental: cada parte do estado é uma "peça móvel", evocê quer o mínimo possível de "peças móveis".Mais complexidade leva a mais bugs!

Comece com o estado queabsolutamente deveestar lá. Por exemplo, você precisará armazenar aanswerpara a entrada e oerror(se existir) para armazenar o último erro:

Então, você precisará de uma variável de estado representando qual dos estados visuais você deseja exibir. Geralmente há mais de uma maneira de representar isso na memória, então você precisará experimentar.

Se você tiver dificuldade para pensar na melhor maneira imediatamente, comece adicionando estado suficiente para tercerteza absolutade que todos os possíveis estados visuais estão cobertos:

Sua primeira ideia provavelmente não será a melhor, mas tudo bem — refatorar o estado faz parte do processo!

Passo 4: Remover quaisquer variáveis de estado não essenciais

Você quer evitar duplicação no conteúdo do estado para rastrear apenas o que é essencial. Gastar um pouco de tempo refatorando a estrutura do seu estado tornará seus componentes mais fáceis de entender, reduzirá a duplicação e evitará significados não intencionais. Seu objetivo éprevenir os casos em que o estado na memória não representa nenhuma interface de usuário válida que você gostaria que um usuário visse.(Por exemplo, você nunca quer mostrar uma mensagem de erro e desabilitar a entrada ao mesmo tempo, ou o usuário não poderá corrigir o erro!)

Aqui estão algumas perguntas que você pode fazer sobre suas variáveis de estado:

  • Esse estado causa um paradoxo?Por exemplo,isTyping e isSubmittingnão podem ser ambostrue. Um paradoxo geralmente significa que o estado não está suficientemente restrito. Existem quatro combinações possíveis de dois booleanos, mas apenas três correspondem a estados válidos. Para remover o estado "impossível", você pode combiná-los em umstatusque deve ser um de três valores:'typing','submitting', ou'success'.
  • A mesma informação já está disponível em outra variável de estado?Outro paradoxo:isEmpty e isTypingnão podem sertrueao mesmo tempo. Ao torná-los variáveis de estado separadas, você corre o risco de elas ficarem dessincronizadas e causarem bugs. Felizmente, você pode removerisEmptye, em vez disso, verificaranswer.length === 0.
  • Você pode obter a mesma informação a partir do inverso de outra variável de estado?isErrornão é necessário porque você pode verificarerror !== nullem vez disso.

Após essa limpeza, você fica com 3 (reduzidas de 7!) variáveis de estadoessenciais:

Você sabe que elas são essenciais porque não pode remover nenhuma delas sem quebrar a funcionalidade.

Deep Dive
Eliminando estados “impossíveis” com um reducer

Etapa 5: Conectar os manipuladores de eventos para definir o estado

Por fim, crie manipuladores de eventos que atualizem o estado. Abaixo está o formulário final, com todos os manipuladores de eventos conectados:

Embora este código seja mais longo que o exemplo imperativo original, ele é muito menos frágil. Expressar todas as interações como mudanças de estado permite que você introduza novos estados visuais posteriormente sem quebrar os existentes. Também permite que você altere o que deve ser exibido em cada estado sem mudar a lógica da interação em si.

Recapitulação

  • Programação declarativa significa descrever a UI para cada estado visual em vez de microgerenciar a UI (imperativo).
  • Ao desenvolver um componente:
    1. Identifique todos os seus estados visuais.
    2. Determine os gatilhos humanos e de computador para mudanças de estado.
    3. Modele o estado comuseState.
    4. Remova estados não essenciais para evitar bugs e paradoxos.
    5. Conecte os manipuladores de eventos para definir o estado.

Try out some challenges

Challenge 1 of 3:Add and remove a CSS class #

Make it so that clicking on the picture removes the background--active CSS class from the outer <div>, but adds the picture--active class to the <img>. Clicking the background again should restore the original CSS classes.

Visually, you should expect that clicking on the picture removes the purple background and highlights the picture border. Clicking outside the picture highlights the background, but removes the picture border highlight.