O problema: lógica repetida
Imagine dois componentes que precisam de um interruptor (ligado/desligado). Em ambos você escreveria a mesma coisa:
const [aberto, setAberto] = useState(false);
const alternar = () => setAberto((v) => !v);
Copiar e colar essa lógica funciona, mas ela se desincroniza com o tempo. A solução do React são os hooks personalizados.
O que é um hook personalizado
Um hook personalizado é, simplesmente, uma função cujo nome começa com
use e que usa outros hooks por dentro. Encapsula lógica com estado e
retorna o que o componente precisa:
function useToggle(inicial = false) {
const [valor, setValor] = useState(inicial);
const alternar = () => setValor((v) => !v);
return [valor, alternar];
}
Agora qualquer componente reutiliza essa lógica sem duplicá-la:
function Painel() {
const [aberto, alternar] = useToggle(false);
return (
<div>
<button onClick={alternar}>Mostrar/ocultar</button>
{aberto && <p>Conteúdo visível</p>}
</div>
);
}
O importante: cada componente que chama useToggle obtém seu próprio
estado, isolado. Você compartilha a lógica, não o estado.
Outro exemplo: useContador
Um hook pode compor vários hooks e expor a API que for mais conveniente (um objeto, um array, funções...):
function useContador(inicial = 0) {
const [cuenta, setCuenta] = useState(inicial);
const incrementar = () => setCuenta((c) => c + 1);
const reiniciar = () => setCuenta(inicial);
return { cuenta, incrementar, reiniciar };
}
As regras dos hooks
Para que o React possa associar cada chamada ao seu estado, os hooks têm duas regras inquebráveis:
- Chame-os somente no nível superior. Nunca dentro de
if, laços, condicionais ou funções aninhadas. A ordem das chamadas deve ser a mesma em cada render. - Chame-os somente a partir de componentes React ou de outros hooks personalizados. Não a partir de funções JavaScript normais.
// ❌ ERRADO: hook dentro de um if (a ordem muda entre renders)
if (ativo) {
const [x, setX] = useState(0);
}
// ✅ CERTO: no nível superior; a condição vai por dentro
const [x, setX] = useState(0);
if (ativo) { /* usa x */ }
Um hook personalizado é apenas uma convenção de nome (
use...) mais estas regras. Não há "mágica": é uma função que organiza seus hooks.
Exemplos
Um hook useToggle reutilizável
function useToggle(inicial) {
const [valor, setValor] = React.useState(inicial);
const alternar = () => setValor((v) => !v);
return [valor, alternar];
}
// Simulação: duas "instâncias" têm estado independente
let estado1 = false, estado2 = true;
console.log("início:", estado1, estado2);