Menu

Hooks personalizados no React: como criar os seus

Um hook personalizado é uma função cujo nome começa com use e que chama outros hooks, para que vários componentes reutilizem a mesma lógica com estado. Construa useToggle, useLocalStorage, useDebounce e useWindowWidth e entenda por que cada chamada recebe o próprio estado.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Um hook personalizado é uma função cujo nome começa com use e que chama outros hooks. Você escreve um quando dois componentes precisam da mesma lógica com estado: leve as chamadas de useState e useEffect para a função, retorne o que o componente precisa e chame-a em cada componente.

Os dois spoilers chamam useToggle, e abrir um deixa o outro fechado. Cada chamada executa o próprio useState, então cada componente recebe o próprio valor. Um hook personalizado compartilha lógica, não estado.

As regras para escrever um

  • O nome começa com use e uma letra maiúscula: useToggle, useOnlineStatus. A regra de lint dos hooks usa o prefixo para encontrar chamadas de hooks e verificá-las.
  • Ele chama pelo menos um hook. Um auxiliar que não chama hooks é uma função comum; chame-o de formatDate, não useFormatDate, para que ele possa ser chamado em qualquer lugar, inclusive dentro de condições.
  • Ele segue as regras dos hooks: chame hooks no nível superior dele e chame-o só a partir de componentes ou de outros hooks personalizados.
  • Ele retorna o que for útil. Um array ([on, toggle]) é prático quando quem chama renomeia os valores; um objeto ({ data, loading, error }) se lê melhor com três ou mais.

useLocalStorage: estado que sobrevive a um recarregamento

O useState esquece tudo ao recarregar. Este hook lê o valor inicial do localStorage e grava de volta cada mudança.

A prévia roda em um frame isolado em que o navegador bloqueia o localStorage, então aqui você vai ver o aviso no Console e o hook volta para estado comum. Em uma página normal, o nome sobrevive a um recarregamento. O try/catch não serve só para esta prévia: modos de navegação privada, cookies bloqueados e uma cota cheia também fazem o armazenamento lançar erros em apps reais. Passar uma função para o useState significa que o armazenamento é lido uma vez, na primeira renderização.

useDebounce: espere o usuário parar de digitar

Uma caixa de busca não deve disparar uma requisição a cada tecla. O useDebounce retorna uma cópia de um valor que só atualiza depois que ele parou de mudar por um intervalo definido.

Digite uma palavra rápido: Typed acompanha cada tecla, Debounced alcança meio segundo depois que você para, e o Console registra uma busca. Cada tecla muda value, então o React executa a limpeza (clearTimeout) antes de iniciar um novo timer. Troque 500 por 0 e cada tecla registra a própria busca.

useWindowWidth: assinar com limpeza

Um hook que ouve o navegador precisa remover o listener quando o componente sai, ou cada montagem deixa um para trás.

Redimensione a janela do navegador e o número acompanha. Clique no botão e o Console mostra o listener sendo removido. Apague o return do efeito e depois monte e desmonte algumas vezes: você recebe uma linha added a cada vez e nenhuma removed, então os listeners antigos se acumulam. Para valores do navegador como este, o useSyncExternalStore é o hook que o React criou para a tarefa, e é uma boa coisa para chamar dentro de um hook personalizado.

A lógica é compartilhada, o estado não

Dois componentes que chamam o mesmo hook recebem duas cópias separadas de tudo o que há dentro dele. Isso surpreende quem espera que um hook funcione como uma variável global.

Clique em qualquer um dos botões e só aquele contador se move. Se os dois devem mostrar o mesmo número, mova o estado para App e passe-o para baixo, ou coloque-o em um context. Um hook personalizado pode envolver esse estado compartilhado por conveniência (useCart() lendo um CartContext), mas o compartilhamento vem do context, não do hook.

Quando escrever um hook personalizado

Extraia um hook quando o mesmo grupo de chamadas de hooks aparece em dois componentes, ou quando a lógica de efeitos de um componente é longa o bastante para que um nome a explique melhor (useOnlineStatus() se lê melhor do que vinte linhas de listeners). Não envolva uma única chamada de useState em um hook só para renomeá-la, e não escreva hooks que só chamam useEffect para definir estado a partir de props; calcule esse valor durante a renderização.

Perguntas frequentes

O que é um hook personalizado no React?

Uma função JavaScript cujo nome começa com use e que chama um ou mais outros hooks. Ela empacota lógica com estado (estado, efeitos, refs) para que qualquer componente a reutilize chamando a função.

Hooks personalizados compartilham estado entre componentes?

Não. Cada chamada a um hook personalizado executa as próprias chamadas de useState e useEffect, então cada componente recebe um estado independente. Para compartilhar o mesmo valor entre componentes, eleve o estado ou coloque-o em um context ou em uma store externa.

Por que o nome de um hook personalizado precisa começar com use?

O nome avisa às regras de lint do React e a outros desenvolvedores que a função chama hooks, então as regras dos hooks valem para ela: chame-a no nível superior, nunca dentro de uma condição ou de um loop. Sem o prefixo, o linter não consegue verificar as chamadas dentro dela.

Um hook personalizado pode retornar JSX?

Ele pode retornar qualquer coisa, mas se retorna JSX costuma ficar melhor escrito como componente. Hooks personalizados normalmente retornam valores e funções, como um array ([value, toggle]) ou um objeto ({ data, error, loading }).

Posso chamar um hook personalizado dentro de um useEffect ou de um event handler?

Não. Um hook personalizado continua sendo um hook, então segue as regras dos hooks: chame-o no nível superior de um componente ou de outro hook personalizado.

Ilustração das linguagens de programação do Coddy

Aprenda a programar com o Coddy

COMEÇAR