React: useRef e manipulação do DOM

Última atualização: 2026-10-26

useRef É como um cofre — você pode guardar qualquer coisa lá dentro, e ela ainda estará lá quando você a retirar. Ao contrário do useState, alterar o valor do ref não fará com que o componente seja renderizado novamente.


1. O que você vai aprender



2. A história de uma barra de pesquisa

Os dois principais usos do useRef

100%
flowchart LR
    subgraph "Uses1: DOMQuote"
        A[useRef] --> B["ref={inputRef}"]
        B --> C["inputRef.current.focus()"]
    end
    
    subgraph "Uses2: Variable-Value Storage"
        D[useRef] --> E[".current = value]
        E --> F[Does not trigger a repaint]
    end
    
    G[forwardRef] --> H[Passed from the parent componentref]
    H --> I[Child Component ExposureDOM]
    
    style A fill:#e3f2fd,stroke:#1565c0
    style D fill:#e8f5e9,stroke:#2e7d32
    style G fill:#fff3e0,stroke:#e65100

(1) Problema: Para selecionar um campo de entrada, é necessário manipular o DOM

Bob criou uma página de busca e queria que a página focasse automaticamente no campo de busca ao carregar:

▶ Experimente

Bob quer usar useState para implementar:

▶ Experimente

(2) Uma solução utilizando useRef

▶ Experimente

Saída:

TEXT
Botões: Select All Text, Scroll to the bottom, Measure the height. Entrada: campo de entrada com foco automático. Efeitos colaterais via useEffect. Referência ao DOM via useRef

Benefícios: useRef retorna um objeto mutável { current: null }, e .current é um elemento DOM real. Não são necessários seletores nem getElementById — é naturalmente compatível com o React.



3. Duas principais formas de uso do useRef

Finalidade ref.current aponta para Aciona uma atualização de renderização Cenários típicos
Referência do DOM Elemento do DOM ❌ Foco, rolagem, medição de dimensões
Armazenamento de variáveis Qualquer valor em JavaScript ❌ ID do temporizador, valor anterior, estado fora de renderização

(1) Caso de uso 1: Referências ao DOM

Os usos mais comuns — recuperar elementos do DOM, manipular o foco, o tamanho, a posição de rolagem e assim por diante.

Operação Código Descrição
Foco inputRef.current.focus() Campo de entrada do foco automático
Selecionar texto inputRef.current.select() Selecionar tudo no campo de entrada
Ir até divRef.current.scrollIntoView() Ir até um elemento específico
Ler dimensões divRef.current.offsetHeight Obter a altura do elemento
Reproduzir vídeo videoRef.current.play() Controlar a reprodução do vídeo

▶ Exemplo: 5 operações comuns no DOM

▶ Experimente

Saída:

TEXT
Foco automático no campo de entrada, botão "Select All Text", lista rolável de 20 linhas (com "Scroll to bottom"), caixa com "Measure the height" → exibe o valor em px

(2) Caso de uso 2: Armazenamento de valores de variáveis (sem acionar uma atualização da tela)

Esse é o truque secreto do useRef — ele armazena qualquer valor, e o componente não será renderizado novamente quando esse valor mudar.

▶ Experimente

4. useRef x useState

Dimensão useRef useState
Valor de retorno { current: initial } [value, setter]
Método de modificação ref.current = newValue setState(newValue)
Renderização após modificação ❌ Não aciona ✅ Aciona uma nova renderização
Quando é lido Lê o valor mais recente imediatamente Não o lê até a próxima renderização
Casos de uso Operações no DOM, IDs de temporizadores, valores anteriores Dados a serem exibidos na interface do usuário
▶ Experimente

Saída:

TEXT
Exibe: "DOM Example of Operation". Botões: Select All Text, Scroll to the bottom, Measure the height. Entrada: campo de entrada com foco automático. useEffect gerencia efeitos colaterais. useRef referencia o DOM/variável

▶ Exemplo: Usando useRef para salvar o valor anterior

▶ Experimente

Saída:

TEXT
Atual: 0, anterior: (first time). Clique em +1 → Atual: 1, anterior: 0. Cada clique mostra o valor atual e o anterior.


5. forwardRef: Componentes pais controlam o DOM dos componentes filhos

Por padrão, os componentes de função não expõem suas próprias referências ao DOM. O uso de forwardRef permite que os componentes filhos recebam o ref do componente pai:

▶ Experimente

6. useImperativeHandle: Expor um método específico

Se você não quiser expor todo o elemento DOM, use useImperativeHandle para expor apenas métodos específicos:

▶ Experimente

7. Exemplo completo: Editor de texto rico

▶ Expandir exemplo executável (107 linhas)
▶ Experimente

Saída:

TEXT
Estado: count (setter: setCount). Botão: setCount(c => c + 1)}>+1. useEffect gerencia efeitos colaterais. useRef referencia o DOM/variável

Resultado esperado: Um editor de texto rico que ofereça suporte a negrito, itálico, sublinhado, listas, títulos H2 e outras opções de formatação; o conteúdo pode ser salvo, carregado ou apagado externamente por meio de um ref.


▶ Exemplo 3: Como usar useRef para fechar uma janela pop-up ao clicar nela de fora

▶ Experimente

Saída:

TEXT
Botão "Menu ▾" → menu suspenso (Profile, Settings, Logout). Clique fora → fecha automaticamente via hook useClickOutside.

Saída:

TEXT
Botão com throttling: cliques rápidos são ignorados (no máximo 1 por segundo). Contador de cliques + feedback "Throttled!". useRef armazena o timestamp de lastClick

▶ Exemplo 4: Usando useRef para armazenar um temporizador na implementação de um botão com limitação de frequência

▶ Experimente

Saída:

TEXT
Clique → "Clicked!" + contador. Clicar novamente dentro de 1s → "Too fast! Wait 1 second." (vermelho). Throttling via timestamp no useRef.

Saída:

TEXT
Exibe: "Click Me". Estado: clicks (setter: setClicks), feedback (setter: setFeedback). Botão: Click Me. useRef referencia o DOM/variável. Comportamento baseado em temporizador

▶ Exemplo 5: Usando o forwardRef para envolver um componente Input que pode receber foco

JSX
const FancyInput = React.forwardRef(function FancyInput({ label, error, ...props }, ref) {
  const internalRef = useRef(null)

  useImperativeHandle(ref, () => ({
    focus: () => internalRef.current?.focus(),
    selectAll: () => {
      const el = internalRef.current
      if (el) { el.focus(); el.select() }
    },
    scrollIntoView: () => internalRef.current?.scrollIntoView({ behavior: 'smooth' }),
  }))

  return (
    <div style={{ marginBottom: 12 }}>
      <label style={{ display: 'block', marginBottom: 4, fontSize: 14, fontWeight: 500 }}>{label}</label>
      <input
        ref={internalRef}
        style={{ width: '100%', padding: 8, borderRadius: 4, border: `1px solid ${error ? '#ff4d4f' : '#d9d9d9'}`, outline: 'none' }}
        {...props}
      />
      {error && <p style={{ color: '#ff4d4f', fontSize: 12, margin: '4px 0 0' }}>{error}</p>}
    </div>
  )
})

function FormWithFancyInput() {
  const emailRef = useRef(null)

  function handleSubmit(e) {
    e.preventDefault()
    emailRef.current?.focus()
  }

  return (
    <form onSubmit={handleSubmit} style={{ maxWidth: 400, margin: '0 auto' }}>
      <h3>Sign Up</h3>
      <FancyInput ref={emailRef} label="Email" type="email" placeholder="you@example.com" />
      <FancyInput label="Password" type="password" placeholder="At least 6 characters" />
      <button type="submit" style={{ padding: '8px 24px', cursor: 'pointer' }}>Submit</button>
    </form>
  )
}
▶ Experimente

Saída:

TEXT
Formulário de cadastro: campos de Email e Password com rótulos e estilo de erro. Ao enviar, o foco vai para email. Expõe os métodos focus(), selectAll(), scrollIntoView().

❓ Perguntas Frequentes

P É necessário usar o forwardRef em todos os componentes?
R Não. Use-o apenas nos seguintes cenários: ① Quando um componente pai precisa manipular diretamente o DOM de um componente filho (por exemplo, para colocar o foco em um campo de entrada ou controlar a reprodução de mídia); ② Ao encapsular componentes de formulário reutilizáveis (para que o componente pai possa controlar o foco ou a seleção). Se você estiver apenas passando dados, basta usar props.
P O useRef pode substituir o useState?
R Não. Alterações no useRef não acionam uma nova renderização do componente, ao passo que o setState sim. Se o seu valor precisar ser exibido na interface do usuário ou afetar o resultado da renderização, você deve usar o useState. Se você estiver simplesmente armazenando “dados que não precisam ser mostrados ao usuário” (como um ID de intervalo, o valor da renderização anterior ou uma instância de WebSocket), use useRef. Pense em useRef como um “contêiner de variáveis que não aciona uma nova renderização”.

📖 Resumo


📝 Exercícios

  1. Exercício básico (Dificuldade ⭐): Crie um componente AutoFocusInput que receba foco automaticamente ao ser montado e forneça dois métodos — focus() e clear() — para que o componente pai os chame.
  2. Exercício avançado (Dificuldade ⭐⭐): Crie um componente ClickCounter, use useRef para rastrear o número de cliques (sem exibi-lo na interface do usuário) e use useEffect para registrar “Clicado X vezes” no console a cada renderização.
  3. Desafio (Dificuldade: ⭐⭐⭐): Crie um componente InfiniteScroll que utilize useRef para detectar quando o elemento sentinela (um elemento específico na parte inferior da página) entrar na área de visualização, acionando o carregamento de mais dados. Utilize a API IntersectionObserver.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%