Hooks: estado e sincronização em componentes React

Fala, dev! Hooks são funções que permitem usar recursos do React em componentes de função e em Hooks personalizados. Neste artigo, vamos trabalhar com estado e sincronização usando useState e useEffect, com exemplos que você pode adaptar em um projeto.

A informação histórica está no anúncio oficial do React 16.8. Para acompanhar os exemplos, tenha familiaridade com funções, arrays, desestruturação e componentes. Em uma aplicação com React Server Components, exemplos interativos como estes precisam ficar em um componente de cliente; frameworks podem exigir a diretiva use client.

Regras básicas antes de começar

  • Chame Hooks como useState e useEffect no topo do componente ou de um Hook personalizado.
  • Evite colocá-los em condições, loops, callbacks ou depois de um retorno condicional.
  • Não os chame em funções comuns que não sejam componentes ou Hooks.

As Regras dos Hooks mantêm a ordem das chamadas entre renderizações. A API use tem regras próprias, incluindo a possibilidade de chamadas condicionais; isso não muda as regras de useState e useEffect.

useState: guardar informações da interface

useState retorna o valor atual e a função que solicita sua atualização. O React usa o valor inicial na primeira renderização. Ao atualizar o estado, você pede uma nova renderização; a variável que já foi lida no evento atual mantém o valor daquele momento.

Contador.jsx
import { useState } from 'react';

export default function Contador() {
  const [cliques, setCliques] = useState(0);

  return (
    <section aria-label="Contador de cliques">
      <p>Cliques: {cliques}</p>
      <button type="button" onClick={() => setCliques(anterior => anterior + 1)}>
        Somar um
      </button>
    </section>
  );
}

Quando o novo valor depende do anterior, a forma funcional torna essa relação explícita. Em objetos e arrays, crie o próximo valor sem modificar diretamente o estado existente. Confira os detalhes na referência de useState.

Entendendo o contador

  1. O componente inicia com zero cliques.
  2. A pessoa aciona o botão e o evento chama a função de atualização.
  3. A função calcula o próximo valor usando o estado anterior.
  4. O React renderiza a interface com esse valor.

Como exercício, acrescente um botão para zerar. Depois implemente um segundo contador independente e observe quais informações precisam de estado próprio.

useEffect: sincronizar com algo externo

useEffect conecta o componente a um sistema externo, como um evento do navegador, um temporizador ou uma biblioteca imperativa. Pense no que será conectado e em como desfazer essa conexão. O efeito não deve ser usado automaticamente para todo cálculo ou resposta a clique.

Relogio.jsx
import { useEffect, useState } from 'react';

export default function Relogio() {
  const [hora, setHora] = useState(null);

  useEffect(() => {
    const atualizar = () => setHora(new Date().toLocaleTimeString('pt-BR'));
    atualizar();
    const intervalo = window.setInterval(atualizar, 1000);

    return () => window.clearInterval(intervalo);
  }, []);

  return <p>Hora local: {hora ?? 'Carregando relógio…'}</p>;
}

O estado inicial não depende do horário: o relógio é atualizado no cliente pelo efeito. A função retornada encerra o intervalo, evitando deixá-lo ativo quando o componente sair da tela.

Dependências e limpeza

Sem um array de dependências, o efeito é executado após cada commit do componente. Com [], ele não depende de valores reativos do componente. Com [valor], a sincronização é refeita quando esse valor muda. Declare todos os valores reativos utilizados no efeito e deixe o lint ajudar.

A limpeza acontece antes de executar novamente um efeito com dependências alteradas e ao desmontar. Efeitos não são executados no servidor. A referência de useEffect descreve esse ciclo; ele não é uma equivalência exata entre Hooks e métodos de ciclo de vida das classes.

Por que o efeito pode aparecer duas vezes no desenvolvimento?

Com StrictMode, o React pode executar um ciclo extra de configuração e limpeza no desenvolvimento para revelar problemas. Em vez de esconder a segunda execução com uma variável, confira se a limpeza realmente desfaz a configuração. Esse comportamento de diagnóstico não representa duas execuções extras em produção. Consulte a documentação do StrictMode.

Quando você não precisa de um efeito

Calcule durante a renderização informações que dependem apenas de props e estado, como um nome completo ou uma lista filtrada. Execute ações provocadas por um clique no próprio manipulador do evento. Guardar valores derivados em um segundo estado costuma criar sincronização desnecessária.

Para buscar dados, considere o mecanismo de carregamento do framework ou uma biblioteca apropriada. Um fetch feito em efeito exige cuidar também de falhas e respostas que chegam fora de ordem. O guia Talvez você não precise de um efeito ajuda a escolher uma abordagem.

Um exercício para consolidar o aprendizado

Crie uma lista de tarefas com um campo de texto e um filtro. Use estado para o texto, as tarefas e o filtro escolhido. Calcule a lista visível durante a renderização. Acrescente um temporizador independente usando o padrão de configuração e limpeza do relógio.

Ao revisar, explique por que cada informação precisa de estado e por que o temporizador precisa de efeito. Se não conseguir explicar um Hook, simplifique o exemplo até enxergar sua função. Depois, avance para React 19 e suas novas features.