Skip to content
This page has been auto-translated and may contain errors.View in English

Hooks

Digamos que um componente precisa lembrar se um dropdown está aberto, ou precisa executar algum código depois que renderiza para sincronizar com um servidor. Essas são tarefas para um hook. Você já usou dois deles: useState dá memória a um componente, e useEffect executa código após uma renderização para alcançar algo fora do React. Esses são os dois que você vai usar mais, e o resto dos built-ins segue o mesmo padrão: você chama uma função dentro do seu componente, e ela te conecta a uma parte da maquinaria do React. O nome dessa função sempre começa com use, e esse prefixo é a definição inteira de um hook.

Um tour pelos built-ins mais comuns

Você não precisa de todo hook no primeiro dia, mas ajuda saber o que tem disponível para reconhecer a ferramenta certa quando um problema chama por ela. Aqui estão os que aparecem mais:

  • useRef mantém um valor mutável que sobrevive renderizações sem causar uma. É também como você consegue uma referência direta a um elemento do DOM quando precisa, como focar um input.
  • useContext lê dados compartilhados de um provider ao redor, então um componente profundamente aninhado consegue alcançar um valor sem você passar ele por cada nível no meio do caminho.
  • useReducer gerencia estado através de uma função reducer, onde cada atualização descreve uma transição do estado atual para o próximo. É uma boa escolha quando mudanças de estado ficam complexas o suficiente para um único useState começar a apertar.
  • useMemo cacheia um valor calculado entre renderizações e só recalcula quando suas dependências mudam.
  • useCallback faz o mesmo para uma função, te devolvendo a mesma instância de função entre renderizações em vez de uma nova a cada vez.

useMemo e useCallback ganham mais espaço depois, quando houver uma história real de performance para contar. Refs e o DOM pega useRef em profundidade. Para useContext e useReducer, este capítulo é o tratamento mais profundo que recebem, então volte aqui quando precisar relembrar. Por enquanto, o ponto é o padrão: um hook é sua forma de entrar em um recurso específico do React, e seu nome te diz que é um hook.

As regras dos hooks

Hooks vêm com duas regras, e o React conta com você seguindo-as.

Primeiro, chame hooks no nível superior do seu componente. Não os chame dentro de uma condição, um loop, ou uma função aninhada. Todo hook que um componente usa deveria rodar em toda renderização, na mesma ordem, toda vez.

jsx
function Profile({ isLoggedIn }) {
  // Errado: este hook só roda às vezes
  if (isLoggedIn) {
    const [name, setName] = useState('')
  }

  // Certo: chame no nível superior, incondicionalmente
  const [name, setName] = useState('')
  // ...depois use isLoggedIn dentro da sua lógica
}

Segundo, chame hooks só de componentes de função React ou de outros hooks customizados. Funções JavaScript regulares não conseguem usar hooks, porque não há uma renderização de componente para o React anexar o estado.

Escrevendo seus próprios hooks

Digamos que vários componentes precisem saber a largura da janela do navegador. Em vez de copiar o mesmo useState e useEffect em cada um, você pode empacotar essa lógica uma vez:

jsx
import { useState, useEffect } from 'react'

function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth)

  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth)
    window.addEventListener('resize', handleResize)
    return () => window.removeEventListener('resize', handleResize)
  }, [])

  return width
}

Agora qualquer componente pode chamar const width = useWindowWidth() e obter um valor que atualiza conforme a janela redimensiona. useWindowWidth é um hook customizado: uma função que chama outros hooks. Esse é o padrão inteiro, e porque é uma função, você consegue dar um nome a uma lógica com estado, colocá-la em um lugar, e reutilizá-la entre componentes. O prefixo use é o que a marca como um hook, tanto para a ferramenta do React quanto para a próxima pessoa lendo seu código. Hooks customizados agrupam os hooks que você já tem em algo reutilizável; eles não adicionam novos poderes ao React.

Algumas regras de ouro para usar essa lista. Recorra a useRef quando você precisa manter um valor, como um ID de timer ou uma prop anterior, que não deveria dispara uma re-renderização quando muda, ou quando você precisa pegar um nó do DOM diretamente. Recorra a useContext quando um valor como o tema atual ou o usuário logado precisa alcançar vários níveis de componentes aninhados, e passá-lo por props em cada nível significaria tocar componentes que de outra forma não se importariam. Recorra a useReducer quando uma única parte do estado tem vários sub-valores que atualizam juntos, ou quando o próximo estado depende de uma ação específica em vez de um novo valor simples, já que um reducer mantém aquela lógica de transição em uma função em vez de espalhada por vários setState. Recorra a useMemo ou useCallback só depois que você notar uma desaceleração real, na maioria das vezes um cálculo caro rodando novamente em cada renderização, ou uma identidade de função que está quebrando memoização em outro lugar, como um filho React.memo'd ou o array de dependências de outro hook.

Nomear e extrair um hook customizado segue seu próprio padrão. O nome sempre começa com use, então tanto a ferramenta do React quanto qualquer um lendo o código consegue dizer que é permitido chamar outros hooks. Quando você percebe a mesma combinação de useState e useEffect, ou qualquer outro hook, aparecendo em mais de um componente, esse é o sinal para extrair: puxe a lógica para sua própria função com prefixo use, tenha-a retornar o que os componentes realmente precisam, um valor, um setter, ou um par de ambos, e chame aquela função de cada componente em vez de repetir a configuração.

As regras não são arbitrárias. O React não conhece os nomes das suas variáveis de estado; ele rastreia os hooks em um componente pela ordem em que são chamados. Primeiro hook, segundo hook, terceiro hook, e assim por diante. Na próxima renderização ele caminha aquela mesma lista na mesma ordem e corresponde cada chamada de volta ao estado que configurou da última vez. Mantenha a ordem idêntica em cada renderização e a correspondência se mantém. Coloque um hook atrás de uma condição e a lista muda no momento que aquela condição vira, então o React alinha o estado errado com a chamada errada e o componente quebra de jeitos confusos. Chamar no nível superior, incondicionalmente, é o que garante uma ordem estável.

useMemo e useCallback merecem uma nota separada. Elas são otimizações manuais: você está dizendo ao React para manter um valor calculado ou uma função para não ter que refazer o trabalho ou entregar uma nova instância em cada renderização. Elas custam um pouco de complexidade, e é tentador alcançá-las onde elas não ajudam de verdade. O React Compiler cada vez mais as torna desnecessárias ao memoizar esse tipo de coisa para você no build, então trate alcançá-las manualmente como algo que você faz deliberadamente, onde você mediu um custo real, em vez de um reflexo em cada valor.

JunoHooks deixam um componente usar recursos do React Um hook é uma função cujo nome começa com use, e ela conecta seu componente a um recurso do React como memória ou effects. Você já conheceu useState e useEffect, e os outros seguem o mesmo padrão. A coisa principal para lembrar: chame hooks no topo do seu componente, nunca dentro de um if ou um loop, então eles rodem do mesmo jeito a cada renderização.
JunoHooks deixam um componente usar recursos do React Além de useState e useEffect, você tem useRef para valores que sobrevivem renderizações sem disparar uma, useContext para evitar prop drilling, useReducer para transições de estado estruturadas, e useMemo/useCallback para caching. Chame-os no nível superior de um componente ou outro hook, sempre na mesma ordem. Quando você se vê repetindo lógica com estado, puxe-a para um hook customizado, uma função use que chama outros hooks, e reutilize-a.
JunoHooks deixam um componente usar recursos do React O React corresponde hooks ao seu estado pela ordem de chamada, não pelo nome, então a ordem tem que ser idêntica em cada renderização. Aquele único fato é de onde as duas regras vêm. Hooks customizados são composição: uma função chamando hooks, é por isso que as mesmas regras de ordenação se aplicam dentro deles. E trate useMemo/useCallback como otimizações deliberadas e medidas, já que o React Compiler está constantemente tornando as versões escritas à mão desnecessárias.

Próximo: Pensando em React, onde componentes, props, estado, e effects se juntam em um processo para transformar um design em uma UI.