useTransition do react js


 
React.js · Hooks · Performance

Como funciona o useTransition do React? Aprenda com exemplos práticos

Você já clicou em um botão de um site e percebeu que a página ficou lenta enquanto o React tentava atualizar a tela? O hook useTransition ajuda a organizar esse trabalho para que as atualizações menos urgentes não atrapalhem as interações mais importantes.

Neste tutorial, você vai aprender o que é o useTransition, como ele funciona por trás dos panos, quando utilizá-lo e como evitar os erros mais comuns. Tudo com exemplos de código em React e JavaScript.

1. O que é o useTransition do React?

O useTransition é um hook do React que permite marcar determinadas atualizações de estado como transições não urgentes.

Um hook é uma função especial do React que permite usar recursos como estado, efeitos e controle de atualizações dentro de componentes funcionais.

Mas o que significa uma atualização não urgente? Imagine que você está digitando em uma caixa de pesquisa. Cada letra que você digita precisa aparecer rapidamente. Essa interação é importante e não deve ficar esperando uma tarefa pesada terminar.

Ao mesmo tempo, o site pode precisar atualizar uma lista enorme de resultados. Essa tarefa pode receber uma prioridade menor para que o React consiga dar preferência a interações urgentes.

Ideia principal:

O useTransition ajuda o React a distinguir uma atualização que precisa responder rapidamente de outra que pode esperar um pouco.

Uma comparação simples

Imagine uma pessoa trabalhando em uma recepção. Ela precisa atender alguém que está fazendo uma pergunta agora e também organizar uma pilha de documentos.

A pergunta da pessoa precisa de atenção imediata. Os documentos podem ser organizados logo depois. O useTransition ajuda o React a tratar certas atualizações como esse segundo trabalho.

Isso não significa que o trabalho pesado desaparece. Significa que o React pode organizar melhor a renderização para dar preferência às interações urgentes.

2. Qual problema o useTransition resolve?

Para entender a utilidade desse hook, primeiro precisamos entender o que acontece quando o estado de um componente muda.

O que é estado?

O estado é uma informação que o React acompanha. Quando essa informação muda, o React pode renderizar novamente o componente para mostrar o novo valor na tela.

Por exemplo, um contador guarda um número:

import { useState } from 'react';

function Contador() {
  const [numero, setNumero] = useState(0);

  return (
    <button
      onClick={() => setNumero(numero + 1)}
    >
      Cliques: {numero}
    </button>
  );
}

Nesse exemplo, clicar no botão altera o estado. O React percebe a mudança e atualiza o número exibido.

Em componentes simples, isso costuma ser rápido. O problema aparece quando uma atualização provoca uma renderização cara, por exemplo, quando muitos componentes precisam calcular e exibir milhares de resultados.

Por que uma página pode ficar lenta?

  1. O usuário realiza uma ação.
  2. O estado do React muda.
  3. O React precisa calcular o que deve aparecer na tela.
  4. Se o trabalho de renderização for pesado, outras atualizações podem precisar esperar.
Atenção:

O useTransition não transforma automaticamente qualquer função lenta em uma função rápida. Ele controla a prioridade de atualizações de estado e a renderização associada a elas. Se o JavaScript bloquear a thread principal com um cálculo pesado e síncrono, o hook sozinho não resolverá esse bloqueio.

Exemplo do cotidiano

Pense em dois trabalhos: mostrar imediatamente o texto digitado e atualizar uma lista extensa de produtos. O texto precisa acompanhar cada tecla; a lista pode ser atualizada como uma transição.

É nesse tipo de situação que o useTransition pode ajudar a tornar a experiência mais responsiva.

3. Como o useTransition funciona por trás dos panos?

O React não atualiza necessariamente todas as partes da interface de uma só vez. Ele possui um sistema de agendamento que organiza as atualizações e pode dar prioridade a algumas renderizações.

Quando você marca uma atualização com startTransition, está avisando ao React que aquela atualização pode ter prioridade menor do que uma interação urgente.

O caminho de uma transição

1
O usuário faz alguma coisa

Por exemplo, digita uma pesquisa ou clica em uma categoria.

2
O código inicia uma transição

O desenvolvedor usa startTransition para marcar a atualização como não urgente.

3
O React agenda o trabalho

O React pode interromper uma renderização de transição para processar uma atualização mais urgente.

4
A interface recebe a atualização

Quando o React termina o trabalho necessário, ele aplica a nova interface.

Uma característica importante é que o React pode abandonar uma tentativa de renderização de transição e recomeçá-la com os dados mais recentes. Isso evita insistir em mostrar resultados intermediários que já ficaram desatualizados.

Essa interrupção acontece no trabalho de renderização do React. Ela não significa que o navegador pode interromper qualquer instrução JavaScript no meio de sua execução.

Um detalhe importante:

O useTransition não é uma ferramenta para executar tarefas em segundo plano, como um Web Worker. Ele ajuda a organizar a prioridade das atualizações de interface.

4. Qual é a sintaxe do useTransition?

O hook retorna duas coisas: uma informação chamada isPending e uma função chamada startTransition.

Veja a estrutura básica:

import { useTransition } from 'react';

function MeuComponente() {
  const [isPending, startTransition] = useTransition();

  // O restante do componente fica aqui.

  return (
    <div>
      {isPending && 'Atualizando...'}
    </div>
  );
}

Entendendo cada parte

1. useTransition

É o hook que fornece as ferramentas para trabalhar com transições.

2. isPending

É um valor booleano: pode ser true ou false. Ele indica se uma transição iniciada por esse hook ainda está pendente.

3. startTransition

É a função usada para marcar as atualizações de estado que devem ser tratadas como transições.

O nome startTransition pode parecer complicado, mas sua ideia é simples: iniciar um trecho de código que contém atualizações não urgentes.

5. Exemplo 1: atualizar uma lista de resultados

Vamos criar uma pequena aplicação que permite digitar o nome de uma fruta e atualizar uma lista de resultados.

A caixa de texto precisa responder imediatamente à digitação. Já a atualização da lista será marcada como uma transição.

Objetivo do exemplo

Separar o estado usado para controlar a digitação do estado usado para exibir os resultados filtrados. Assim, a digitação continua sendo uma atualização urgente, enquanto a lista pode ser atualizada com prioridade menor.

Código completo

import { useState, useTransition } from 'react';

const frutas = [
  'Maçã',
  'Banana',
  'Laranja',
  'Morango',
  'Abacaxi',
  'Uva'
];

export default function PesquisaFrutas() {
  const [texto, setTexto] = useState('');
  const [resultado, setResultado] = useState(frutas);
  const [isPending, startTransition] = useTransition();

  function handleChange(event) {
    const valor = event.target.value;

    // Atualização urgente: a caixa acompanha a digitação.
    setTexto(valor);

    // Atualização não urgente: atualizar os resultados.
    startTransition(() => {
      setResultado(
        frutas.filter((fruta) =>
          fruta.toLowerCase().includes(valor.toLowerCase())
        )
      );
    });
  }

  return (
    <section>
      <h2>Pesquisar frutas</h2>

      <input
        value={texto}
        onChange={handleChange}
        placeholder="Digite uma fruta"
      />

      {isPending && (
        <p>Atualizando resultados...</p>
      )}

      <ul>
        {resultado.map((fruta) => (
          <li key={fruta} >
            {fruta}
          </li>
        ))}
      </ul>
    </section>
  );
}

Explicando as partes importantes

1. Criamos dois estados diferentes.

const [texto, setTexto] = useState('');
const [resultado, setResultado] = useState(frutas);

O estado texto guarda o que está escrito na caixa. O estado resultado guarda as frutas que aparecem na lista.

2. Atualizamos a caixa imediatamente.

setTexto(valor);

Essa atualização fica fora da transição. Dessa forma, o valor digitado não é tratado como uma atualização não urgente.

3. Marcamos a atualização da lista.

startTransition(() => {
  setResultado(
    frutas.filter((fruta) =>
      fruta.toLowerCase().includes(valor.toLowerCase())
    )
  );
});

O React pode dar prioridade menor à atualização do estado resultado. O filtro, nesse caso, é um cálculo simples. O benefício do useTransition fica mais evidente quando a renderização da lista é custosa.

Resultado esperado

Você digita: ma
Resultados: Maçã

Ao digitar letras diferentes, a caixa continua usando o estado urgente. A lista é atualizada conforme a transição é processada.

Neste exemplo pequeno, talvez você não perceba diferença de velocidade. Isso é normal: a lista é pequena e o navegador consegue processá-la rapidamente.

Por que esse exemplo funciona?

Porque o React consegue tratar a atualização da lista como menos urgente sem colocar a atualização da caixa de texto dentro da mesma transição.

Observação: em aplicações com milhares de itens, o cálculo do filtro ainda pode consumir bastante tempo na thread principal. Se o próprio cálculo for caro, considere também otimizar os dados, usar virtualização ou mover cálculos pesados para um Web Worker.

6. Exemplo 2: alternar entre telas sem priorizar a renderização pesada

Imagine um painel com duas telas: uma lista de produtos e uma lista de pedidos. A mudança de tela pode provocar uma renderização cara.

Vamos marcar a atualização da tela selecionada como uma transição e mostrar uma mensagem enquanto ela estiver pendente.

Código do exemplo

import { useState, useTransition } from 'react';

function Produtos() {
  return <h2>Lista de produtos</h2>;
}

function Pedidos() {
  return <h2>Lista de pedidos</h2>;
}

export default function Painel() {
  const [tela, setTela] = useState('produtos');
  const [isPending, startTransition] = useTransition();

  function abrirTela(novaTela) {
    startTransition(() => {
      setTela(novaTela);
    });
  }

  return (
    <div>
      <button
        onClick={() => abrirTela('produtos')}
      >
        Produtos
      </button>

      <button
        onClick={() => abrirTela('pedidos')}
      >
        Pedidos
      </button>

      {isPending && (
        <p>Preparando a tela...</p>
      )}

      {tela === 'produtos' ? <Produtos /> : <Pedidos />}
    </div>
  );
}

O que acontece aqui?

  1. O usuário clica em Produtos ou Pedidos.
  2. A função abrirTela recebe o nome da tela escolhida.
  3. O estado tela é atualizado dentro de startTransition.
  4. O React trata a atualização como uma transição.
  5. O componente mostra a mensagem de espera se isPending estiver verdadeiro.

Nesse exemplo, as telas são leves. Por isso, a mensagem pode aparecer por pouco tempo ou nem chegar a ser percebida.

Quando esse padrão é útil?

Quando trocar de tela, aba ou categoria provoca uma renderização cara e você quer que o React consiga dar prioridade a outras interações urgentes.

7. Para que serve o isPending?

O isPending permite saber se uma transição iniciada pelo hook continua pendente. Com essa informação, você pode exibir um indicador de carregamento ou mudar a aparência de uma área.

Imagine que você pediu para alguém preparar um lanche. Enquanto a pessoa está preparando, você vê uma mensagem dizendo que o pedido está em andamento. O isPending funciona como esse aviso, mas para a transição da interface.

Exemplo curto

const [isPending, startTransition] = useTransition();

return (
  <div>
    {isPending && (
      <p>Atualizando a interface...</p>
    )}
  </div>
);

O operador && permite mostrar o parágrafo apenas quando a condição for verdadeira.

Se isPending for verdadeiro, o texto aparecerá. Se for falso, o React não exibirá esse parágrafo.

Importante:

isPending não é um cronômetro e não significa necessariamente que uma requisição HTTP está acontecendo. Ele indica o estado pendente da transição acompanhada por esse hook.

8. O que faz o startTransition?

O startTransition é a função que marca atualizações de estado como não urgentes. Ele recebe uma função e executa essa função imediatamente para iniciar as atualizações.

Isso é diferente de colocar um código dentro de um temporizador. O startTransition não espera um tempo determinado e não cria uma nova thread.

Exemplo: atualização normal

setCategoria('tecnologia');

Essa atualização não foi marcada explicitamente como uma transição.

Exemplo: atualização como transição

startTransition(() => {
  setCategoria('tecnologia');
});

Agora, o React sabe que a atualização pode receber uma prioridade menor do que as atualizações urgentes.

A atualização de estado marcada como transição não deve ser usada para controlar diretamente o valor de um campo de formulário que precisa acompanhar cada tecla. Para isso, mantenha um estado urgente e, se necessário, separe o estado usado para atualizar resultados.

Posso usar o useTransition sem criar uma variável isPending?

O hook retorna os dois valores, mas você pode ignorar o primeiro se não precisar dele:

const [, startTransition] = useTransition();

O espaço antes da vírgula indica que você não quer guardar o primeiro valor. O segundo continua disponível para iniciar as transições.

9. Erros comuns ao usar useTransition

Erro 1: colocar o estado do campo de texto na transição

Problema:

startTransition(() => {
  setTexto(event.target.value);
});

Se esse estado controla diretamente um campo de texto, você está marcando como não urgente uma atualização que precisa acompanhar a digitação.

Solução:

// Estado do campo: urgente.
setTexto(event.target.value);

// Estado dos resultados: pode ser uma transição.
startTransition(() => {
  setResultado(novosResultados);
});

Separe o estado do campo do estado usado para renderizar os resultados.

Erro 2: achar que o hook acelera qualquer cálculo

O useTransition não torna automaticamente mais rápido um cálculo pesado que bloqueia o JavaScript.

Solução:

  • Reduza o trabalho desnecessário.
  • Use técnicas como virtualização para listas enormes.
  • Considere um Web Worker para cálculos realmente pesados.
  • Use o React Profiler para descobrir o que está causando lentidão.

Erro 3: tentar usar useTransition fora de um componente React

Hooks como useTransition devem ser chamados no nível superior de um componente funcional ou de um hook personalizado.

Incorreto:

function minhaFuncao() {
  const [isPending, startTransition] = useTransition();
}

Essa função comum não é, por si só, um componente React nem um hook personalizado.

Solução:

function MeuComponente() {
  const [isPending, startTransition] = useTransition();

  // Use os valores dentro do componente.

  return <div>Meu componente</div>;
}

Erro 4: esperar que atualizações após await sejam sempre transições

Existe um detalhe importante ao trabalhar com operações assíncronas.

startTransition(async () => {
  const dados = await buscarDados();

  // Esta atualização pode precisar de outra transição.
  startTransition(() => {
    setDados(dados);
  });
});

Em versões atuais do React que oferecem suporte a funções assíncronas em transições, atualizações de estado realizadas depois de um await ainda podem exigir outro startTransition para serem marcadas como transições.

A sintaxe assíncrona também depende da versão do React e do contexto utilizado. Consulte a documentação oficial antes de aplicar esse padrão em projetos com versões diferentes.

10. Boas práticas para usar useTransition

  • Use em atualizações que podem esperar: filtros grandes, troca de abas ou atualizações visuais custosas são exemplos possíveis.
  • Mantenha interações urgentes separadas: campos de texto controlados devem continuar respondendo imediatamente.
  • Meça antes de otimizar: não é necessário usar useTransition em todos os componentes.
  • Mostre um indicador quando fizer sentido: use isPending para informar que uma transição está em andamento.
  • Não confunda prioridade com velocidade de cálculo: cálculos longos e síncronos podem exigir outra estratégia.
  • Evite estados duplicados sem necessidade: mantenha separados apenas os estados que têm funções diferentes.
  • Use componentes menores quando possível: isso pode reduzir a quantidade de trabalho necessária para renderizar a interface.

Qual é a diferença entre useTransition e useDeferredValue?

Os dois recursos ajudam a manter a interface responsiva, mas funcionam de maneiras diferentes.

Recurso Como funciona Quando considerar
useTransition Permite marcar atualizações de estado como transições. Quando você controla a atualização e quer marcá-la como não urgente.
useDeferredValue Permite usar uma versão adiada de um valor. Quando você recebe um valor e quer que uma parte da interface possa acompanhar uma versão atualizada com menor prioridade.

Por exemplo, você pode usar useTransition para marcar uma mudança de categoria iniciada por um botão. Já useDeferredValue pode ajudar quando um campo de pesquisa precisa responder rapidamente, mas uma lista pode renderizar usando uma versão adiada do texto.

Nenhum dos dois substitui a necessidade de identificar a causa real de uma lentidão.

11. Exercício para praticar

Agora é sua vez de testar o que aprendeu. Crie um componente com dois botões: um chamado Notícias e outro chamado Tecnologia.

O objetivo é:

  1. Criar um estado chamado categoria.
  2. Inicializar esse estado com o valor 'noticias'.
  3. Criar outro estado chamado isPending usando useTransition.
  4. Ao clicar em cada botão, atualizar a categoria dentro de startTransition.
  5. Exibir uma mensagem enquanto a transição estiver pendente.
  6. Mostrar na tela qual categoria está selecionada.
Dica:

Use uma condição para mostrar o conteúdo correto de acordo com a categoria. Não se preocupe se a transição for rápida demais para você perceber a mensagem de espera.

Confira a ideia da solução

const [categoria, setCategoria] = useState('noticias');
const [isPending, startTransition] = useTransition();

function selecionarCategoria(novaCategoria) {
  startTransition(() => {
    setCategoria(novaCategoria);
  });
}

Complete o componente criando os botões e exibindo o conteúdo correspondente à categoria escolhida.

12. Resumo: o que você precisa lembrar

  • useTransition: hook do React que ajuda a marcar atualizações como não urgentes.
  • startTransition: função que envolve atualizações de estado que podem receber prioridade menor.
  • isPending: informa se uma transição acompanhada pelo hook está pendente.
  • Renderização interrompível: o React pode dar preferência a atualizações mais urgentes durante uma transição.
  • Campos de texto: mantenha o estado que controla a digitação fora da transição.
  • Limite: o hook não resolve sozinho cálculos síncronos muito pesados.

13. Conclusão

O useTransition é uma ferramenta importante para construir interfaces React que continuam responsivas mesmo quando certas atualizações exigem mais trabalho de renderização.

O segredo não é usar esse hook em todos os lugares. É identificar quais atualizações precisam responder imediatamente e quais podem ser tratadas como menos urgentes.

Comece com exemplos pequenos, como alternar entre abas ou atualizar listas. Depois, aplique o conceito em partes maiores da aplicação e compare o comportamento antes e depois da mudança.

Para aprofundar seu conhecimento, consulte também a documentação oficial do React: useTransition — documentação oficial do React.

RECURSO RECOMENDADO

Quer continuar aprendendo programação?

Conheça o curso Torne-se um Programador Fullstack e domine o mercado digital! e avalie se a proposta combina com seus objetivos de estudo.

Se você deseja ampliar seus conhecimentos além deste tutorial de React, esse pode ser um recurso complementar para pesquisar antes de escolher seu próximo passo.

O que você pode avaliar antes de se inscrever:

  • Se o conteúdo combina com o seu nível atual de conhecimento.
  • Se os assuntos ensinados correspondem ao que você deseja aprender.
  • Se a proposta do curso faz sentido para seus objetivos de programação.
Conhecer o curso →

Transparência: este artigo contém um link de afiliado. Podemos receber uma comissão caso você realize uma compra por meio dele, sem custo adicional para você. Consulte as informações e condições diretamente na página do curso antes de tomar sua decisão.

Artigo educativo sobre React.js, hooks, renderização e otimização da experiência do usuário.


Comentários

Postagens mais visitadas deste blog

useMemo do React js

useEffect do React js

useState do React js