Concurrent Features do React 18
useTransition, useDeferredValue, Suspense para data fetching. O que é renderização concorrente.
Definição
React 18 introduziu renderização concorrente: o React pode pausar, retomar e abandonar renderizações. Isso permite priorizar atualizações urgentes (digitação, clique) sobre não-urgentes (atualização de lista filtrada). useTransition marca updates como não-urgentes. useDeferredValue adia o processamento de um valor. Suspense para data fetching permite mostrar fallback enquanto aguarda dados.
Problema → Solução
Problema
Filtrar uma lista grande enquanto o usuário digita trava a UI: cada keystroke dispara re-render de toda a lista filtrada. O input fica lento e a UX ruim.Solução
useTransition: marca a atualização da lista como transição (não-urgente). O input atualiza imediatamente, a lista filtra quando há tempo. isPending indica que há transição em andamento para mostrar indicador visual.Dica de entrevista
Tip
useTransition é para quando VOCÊ controla o estado. useDeferredValue é para quando você recebe um valor como prop ou de outra source e não pode adicionar startTransition na origem. Em geral: prefira useTransition. Use useDeferredValue quando não tem acesso ao setter.Código
// useTransition — filtro de lista pesada sem travar input
import { useState, useTransition } from 'react'
function SearchPage({ items }: { items: Item[] }) {
const [query, setQuery] = useState('')
const [filtered, setFiltered] = useState(items)
const [isPending, startTransition] = useTransition()
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
const value = e.target.value
setQuery(value) // urgente — input atualiza imediatamente
startTransition(() => {
// não-urgente — pode ser interrompido por nova digitação
setFiltered(items.filter(item =>
item.name.toLowerCase().includes(value.toLowerCase())
))
})
}
return (
<>
<input value={query} onChange={handleChange} />
{isPending && <Spinner />}
<List items={filtered} />
</>
)
}
// useDeferredValue — quando não controla o setter
function FilteredList({ query }: { query: string }) {
const deferredQuery = useDeferredValue(query)
// deferredQuery fica "atrás" de query durante digitação rápida
const filtered = useMemo(
() => items.filter(i => i.name.includes(deferredQuery)),
[deferredQuery]
)
return <List items={filtered} />
}Perguntas de entrevista
Q.Qual a diferença entre useTransition e useDeferredValue?▾
A.useTransition: você controla quando o update é não-urgente — wrapping o setState com startTransition. useDeferredValue: você recebe um valor e cria uma versão "atrasada" dele — útil quando não controla a origem do update (prop de pai, etc). Ambos usam a mesma mecânica de concorrência.
Q.O que é Suspense para data fetching?▾
A.Permite que um componente "suspenda" sua renderização até que os dados estejam prontos, mostrando o fallback do Suspense mais próximo. React Query e SWR têm suporte experimental. Com Next.js App Router: `use(promise)` ou React Server Components fazem fetch suspense-aware nativamente. Simplifica loading states: um `<Suspense>` cobre múltiplos componentes filhos.
Q.Quando NÃO usar useTransition?▾
A.Para updates de input controlado — o valor do input deve ser sempre síncrono. Para animações — use CSS ou Framer Motion. Para feedback imediato que o usuário espera ser instantâneo. useTransition é para cálculos pesados que podem ser adiados, não para tudo.
Termos relacionados
81/122← →