Estado de um Componente

O que setState faz?

setState() agenda uma atualização para o objeto state de um componente. Quando o estado muda, o componente responde renderizando novamente.

Qual é a diferença entre state e props?

props (abreviação de ”properties”) and state são ambos objetos JavaScript. Apesar de ambos guardarem informações que influenciam no resultado da renderização, eles são diferentes por uma razão importante: props são passados para o componente (como parâmetros de funções), enquanto state é gerido de dentro do componente (como variáveis declaradas dentro de uma função).

Aqui estão alguns bons recursos para ler mais sobre quando usar props vs state (ambos em inglês):

Porquê setState está a dar-me o valor errado?

Em React, tanto this.props quanto this.state representam os valores renderizados, ou seja, o que está atualmente na tela.

Chamadas para setState são assíncronas - não confie que this.state vá refletir o novo valor imediatamente após chamar setState. Usa uma função de atualização ao invés de um objeto se precisas calcular valores baseado no estado atual (vê abaixo para mais detalhes).

Exemplo de código que não vai funcionar como esperado:

incrementCount() {
  // Nota: isso *não* vai funcionar como esperado.
  this.setState({count: this.state.count + 1});
}

handleSomething() {
  // Digamos que `this.state.count` começa em 0.
  this.incrementCount();
  this.incrementCount();
  this.incrementCount();
  // Quando o React renderizar novamente o componente, `this.state.count` será 1, mas tu esperavas 3.

  // Isto é porque a função `incrementCount()` usa `this.state.count`,
  // mas o React não atualiza `this.state.count` até o componente ser renderizado novamente.
  // Então `incrementCount()` lê `this.state.count` como 0 todas as vezes, e muda seu valor para 1.

  // A solução é descrita abaixo!
}

Vê abaixo como solucionar esse problema.

Como atualizar o state com valores que dependem do state atual?

Passa uma função ao invés de um objeto para setState para garantir que a chamada sempre use o valor mais recente do estado (vê abaixo).

Qual é a diferença entre passar um objeto e uma função em setState?

Passar uma função de atualização permite que acesses o valor atual do state dentro dela. Como as chamadas de setState são feitas em lotes, isso permite que você encadeie atualizações e garanta que elas se componham ao invés de entrar em conflito:

incrementCount() {
  this.setState((state) => {
    // Importante: use `state` em vez de `this.state` quando estiveres a atualizar.
    return {count: state.count + 1}
  });
}

handleSomething() {
  // Digamos que `this.state.count` começa em 0.
  this.incrementCount();
  this.incrementCount();
  this.incrementCount();

  // Se fores a ler `this.state.count` agora, ele ainda seria 0.
  // Mas quando o React renderizar novamente o componente, ele será 3.
}

Lê mais sobre setState

Quando é que setState é assíncrono?

Atualmente, setState é assíncrono dentro de manipuladores de evento.

Isto garante que, por exemplo, caso tanto Parent quanto Child chamem setState após um evento de clique, Child não seja renderizado duas vezes. Em vez disso, React executa todas as atualizações de estado ao final do evento do navegador. Isto resulta numa melhoria de performance significativa para aplicativos maiores.

Isto é um detalhe de implementação, então evita depender disso diretamente. Em versões futuras, o React fará atualizações em lotes em mais casos.

Porquê é que o React não atualiza this.state de forma síncrona?

Como explicado na seção anterior, React intencionalmente “espera” até todos os componentes terem chamado setState() em seus manipuladores de evento antes de começar a renderizar novamente. Isso aumenta performance por evitar renderizações desnecessárias.

No entanto, podes ainda questionar porquê o React simplesmente não atualiza this.state imediatamente, sem renderizar novamente.

Existem duas principais razões:

  • Isso quebraria a consistência entre props e state, causando problemas muito difíceis de debugar.
  • Isso tornaria algumas das novas funcionalidades em que estamos a trabalhar impossíveis de implementar.

Este comentário no GitHub aprofunda mais com exemplos específicos.

Devo usar uma biblioteca de gestão de estado, como Redux ou MobX?

Talvez.

É uma boa ideia aprofundar-se em React primeiro, antes de adicionar bibliotecas. Podes fazer aplicativos muito complexos apenas com React.