FS

Você realmente entende como o useState funciona?

Imagem do post Você realmente entende como o useState funciona?

Entenda por que o useState não atualiza o valor imediatamente e evite os erros mais comuns em componentes React.

Quando falamos em React, um dos primeiros conceitos que aprendemos é o useState. Ele é simples, fácil de usar e muito poderoso. Mas justamente por parecer simples, muita gente acaba usando de forma incorreta — e aí surgem aqueles bugs que são difíceis de entender e ainda mais difíceis de encontrar.

Neste artigo, vou te mostrar o que realmente acontece quando você chama setState, e como isso pode afetar o comportamento do seu componente se você não estiver atento.

O que acontece quando você usa setState?

Diferente de outras tecnologias reativas, o React não atualiza o valor na hora.

Quando você chama setState, o React agenda uma atualização. Ou seja, o novo valor só vai ser aplicado depois que o componente terminar de renderizar.

Exemplo clássico:

setCount(count + 1) 
console.log(count) // Ainda mostra o valor antigo!

Esse comportamento pode gerar diversos problemas se você tentar usar o valor atualizado logo após o setState.

Exemplo 1 – Incrementos consecutivos

setCount(count + 1) 
setCount(count + 1)

Aqui, você pode esperar que o valor aumente em 2, mas o que acontece na prática é que ambas as chamadas usam o mesmo valor anterior de count, então o estado só vai para +1.

Como resolver:

setCount(prev => prev + 1) 
setCount(prev => prev + 1)

Usar a função no setState garante que você está sempre trabalhando com o valor mais recente.

PS: prev vem de previous, ou seja, o valor anterior.

Exemplo 2 – Sobrescrevendo objetos

Outro erro comum ocorre ao atualizar estados que são objetos, como em um formulário:

setForm({ ...form, name: 'Ana' }) 
setForm({ ...form, email: 'ana@email.com' })

O problema aqui é que a segunda chamada pode sobrescrever a primeira, porque ambas estão usando o mesmo valor antigo de form.

Solução:

setForm(prev => ({ ...prev, name: 'Ana' }))
setForm(prev => ({ ...prev, email: 'ana@email.com' }))

Exemplo 3 – Estado em chamadas de API

Você atualiza o estado e logo em seguida quer usar o novo valor:

setUserId(42)
fetch(`/api/user/${userId}`) // ❌ userId ainda é o antigo! 

O valor de userId ainda não mudou. Por isso, o ideal aqui é usar a própria variável que você acabou de definir:

const newId = 42 setUserId(newId)
fetch(`/api/user/${newId}`)

Exemplo 4 – Condições enganadoras

if (!isOpen) {
  setIsOpen(true)
}

Se o valor de isOpen ainda não foi atualizado, esse tipo de lógica pode quebrar. O mais seguro é trabalhar com a função que acessa o valor anterior:

setIsOpen(prev => !prev ? true : prev)

Exemplo 5 – useEffect com dependência errada

useEffect(() => {
  if (count === 5) alert('Chegou em 5!')
}, []) // ❌ Não será executado quando count mudar 

Aqui, você precisa garantir que o useEffect escute as mudanças do estado:

useEffect(() => {
  if (count === 5) alert('Chegou em 5!')
}, [count])

Conclusão

O useState parece simples, mas se você não entende como ele realmente funciona, é fácil cair em armadilhas. Lembre-se:

  • setState não muda o valor imediatamente

  • Sempre que possível, use setState(prev => ...)

  • Evite depender do novo valor logo após atualizá-lo

  • Reaja a mudanças de estado com useEffect

Essa compreensão muda completamente a forma como você escreve componentes e te ajuda a evitar bugs difíceis de rastrear.

Post criado/atualizado em: 24/04/2025

Felipe Santiago

Autor: Felipe Santiago

Trabalho com desenvolvimento web Frontend desde 2023 com foco em React e Typescript. TailwindCSS foi uma reviravolta em meus projetos, não consigo mais ficar sem ele. Evoluindo para aplicações FullStack, foquei muito para criação de APIs com Node e Fastify/Express e manutenção de banco de dados como PostgreSQL.