Menu

Hook useState no React: exemplos e erros comuns

useState dá a um componente um valor que sobrevive às re-renderizações e um setter que redesenha a tela quando o valor muda. Aprenda a sintaxe, as funções de atualização, objetos e arrays no estado e por que um valor parece desatualizado logo depois de você defini-lo.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

useState é o hook que permite a um componente lembrar de algo entre renderizações: uma contagem, o texto de um input, se um menu está aberto. Toda vez que você chama o setter dele, o React renderiza o componente de novo com o novo valor.

Clique no botão e depois troque useState(0) por useState(10) no editor. A prévia é reconstruída e a contagem começa em 10.

A sintaxe

const [value, setValue] = useState(initialValue);
  • initialValue é usado somente na primeira renderização. Em todas as renderizações seguintes o React o ignora e devolve o valor que guardou.
  • value é o valor atual para esta renderização.
  • setValue substitui o valor e agenda uma nova renderização.

Os nomes são seus. useState retorna um array de dois itens e os colchetes o desempacotam, então [isOpen, setIsOpen] e [email, setEmail] são o mesmo padrão.

Chame useState no nível superior do seu componente, nunca dentro de um loop, de uma condição ou de uma função aninhada. O React associa cada chamada ao seu valor guardado pela ordem das chamadas, então essa ordem precisa ser a mesma em toda renderização (veja as regras dos hooks).

Várias partes de estado

Um componente pode chamar useState quantas vezes precisar. Cada chamada é um valor próprio e independente.

O estado é uma foto

O setter não muda a variável que está nas suas mãos. Ele diz ao React qual deve ser o valor na próxima renderização. Até essa renderização acontecer, a atual continua vendo o valor antigo.

Abra o console abaixo da prévia e clique uma vez. O handler registra 0, o valor antigo, e depois o componente registra uma nova renderização com 1. Não há nada de errado: count é uma constante durante toda a renderização, e a próxima renderização recebe uma nova.

Funções de atualização

Por causa da foto, chamar o setter três vezes com count + 1 soma um, não três: cada chamada calcula 0 + 1. Passe uma função em vez disso e o React entrega a cada chamada o resultado da anterior.

Use a forma com função de atualização sempre que o próximo valor depender do anterior e a atualização puder não partir direto da renderização mais recente: vários sets em um handler, um callback de setInterval ou um efeito.

Objetos e arrays no estado

O React decide se renderiza de novo comparando o valor antigo e o novo com Object.is. Se você altera um objeto no lugar e passa o mesmo objeto de volta, a comparação diz que nada mudou e a tela fica como estava. Sempre passe um novo objeto ou array.

{ ...user, age: user.age + 1 } copia todos os campos e sobrescreve um. [...tags, 'code'] adiciona um item, e filter remove um, os dois retornando um novo array. A página sobre atualizar arrays e objetos trata de objetos aninhados, de editar um item de uma lista e de inserir no meio.

Estado inicial preguiçoso

O argumento de useState é avaliado em toda renderização, mesmo que o React só o use na primeira vez. Quando calculá-lo é caro (ler o localStorage, analisar uma string grande), passe uma função. O React a chama uma vez, na primeira renderização.

// Runs readSavedNotes() on every render, then throws the result away
const [notes, setNotes] = useState(readSavedNotes());

// Runs it once
const [notes, setNotes] = useState(readSavedNotes);
const [notes, setNotes] = useState(() => readSavedNotes());

Reiniciar o estado com uma key

O estado pertence à posição de um componente na árvore. Se você renderiza uma key diferente no mesmo lugar, o React trata como um novo componente e o estado dele recomeça. Essa é a forma mais limpa de reiniciar um formulário quando aquilo que ele edita muda.

Digite uma mensagem e depois troque o destinatário: o rascunho é apagado. Remova key={to} e tente de novo, e o texto continua, porque agora o React vê o mesmo Draft no mesmo lugar.

Erros comuns

Registrar o estado logo depois de defini-lo. Você vê o valor antigo, como mostrado acima. Registre no corpo do componente, ou calcule primeiro o próximo valor em uma variável e use essa variável.

Mutar o estado. user.age++; setUser(user) passa o mesmo objeto, então nada é renderizado. Copie primeiro.

Chamar o setter durante a renderização. <button onClick={setCount(count + 1)}> chama setCount durante a renderização, o que renderiza de novo, o que chama de novo. O React interrompe esse loop com "Too many re-renders". Passe uma função: onClick={() => setCount(count + 1)}.

Guardar valores que você pode calcular. Se fullName é sempre first + ' ' + last, calcule durante a renderização em vez de manter uma terceira parte de estado que pode ficar dessincronizada.

Perguntas frequentes

O que o useState retorna?

Um array com exatamente dois itens: o valor atual e uma função que o substitui. Você mesmo dá os nomes com a desestruturação de arrays, por convenção [thing, setThing].

Por que meu estado não atualiza na hora?

Chamar o setter não muda a variável que você já tem. Ele pede ao React para renderizar o componente de novo, e o novo valor aparece nessa próxima renderização. Dentro do event handler atual o valor antigo ainda está no escopo, então console.log(count) logo depois de setCount(count + 1) imprime o número antigo.

Quando devo passar uma função para o setter?

Quando o novo valor depende do antigo e você o define mais de uma vez, ou de dentro de um timer ou de um efeito. setCount(c => c + 1) sempre parte do valor mais recente, enquanto setCount(count + 1) parte do valor que esta renderização viu.

O useState pode guardar um objeto ou um array?

Sim, mas trate-o como somente leitura. Crie um novo objeto ou array e passe-o para o setter (setUser({ ...user, name }), setItems([...items, item])). Alterar o existente no lugar não dispara uma renderização.

Qual é a diferença entre useState e useReducer?

Os dois armazenam estado. O useState serve para alguns valores independentes. O useReducer leva a lógica de atualização para uma única função que recebe uma ação, o que fica mais legível quando muitos eventos mudam o mesmo estado de formas relacionadas.

Ilustração das linguagens de programação do Coddy

Aprenda a programar com o Coddy

COMEÇAR