Resumo de Hooks do React
Resumo de Hooks do React
Hooks Básicos
useState
Permite adicionar estado a componentes funcionais.
import { useState } from 'react';
function Contador() {
const [count, setCount] = useState(0);
return (
<div>
<p>Você clicou {count} vezes</p>
<button onClick={() => setCount(count + 1)}>
Clique aqui
</button>
</div>
);
}
Com função de atualização:
function Contador() {
const [count, setCount] = useState(0);
const incrementar = () => {
setCount(prevCount => prevCount + 1);
};
return <button onClick={incrementar}>Incrementar</button>;
}
useEffect
Executa efeitos colaterais em componentes funcionais.
import { useState, useEffect } from 'react';
function ExemploEffect() {
const [dados, setDados] = useState(null);
useEffect(() => {
// Executa após a renderização
fetch('https://api.exemplo.com/dados')
.then(res => res.json())
.then(data => setDados(data));
// Função de limpeza (cleanup)
return () => {
console.log('Limpeza do efeito');
};
}, []); // Array vazio = executa apenas uma vez
return <div>{dados ? JSON.stringify(dados) : 'Carregando...'}</div>;
}
Com dependências:
function Busca({ termo }) {
const [resultados, setResultados] = useState([]);
useEffect(() => {
if (termo) {
fetch(`/api/busca?q=${termo}`)
.then(res => res.json())
.then(setResultados);
}
}, [termo]); // Re-executa quando 'termo' muda
return <ul>{resultados.map(r => <li key={r.id}>{r.nome}</li>)}</ul>;
}
useContext
Consome valores de um contexto React.
import { createContext, useContext, useState } from 'react';
const TemaContext = createContext();
function App() {
const [tema, setTema] = useState('claro');
return (
<TemaContext.Provider value={{ tema, setTema }}>
<Toolbar />
</TemaContext.Provider>
);
}
function Toolbar() {
const { tema, setTema } = useContext(TemaContext);
return (
<div style={{ background: tema === 'claro' ? '#fff' : '#333' }}>
<button onClick={() => setTema(tema === 'claro' ? 'escuro' : 'claro')}>
Alternar Tema
</button>
</div>
);
}
Hooks Adicionais
useReducer
Alternativa ao useState para lógica de estado mais complexa.
import { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
case 'reset':
return initialState;
default:
throw new Error();
}
}
function Contador() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Contagem: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
</div>
);
}
useCallback
Memoriza uma função para evitar re-criações desnecessárias.
import { useState, useCallback } from 'react';
function ListaDeTarefas() {
const [tarefas, setTarefas] = useState([]);
const adicionarTarefa = useCallback((texto) => {
setTarefas(prev => [...prev, { id: Date.now(), texto }]);
}, []); // Função não muda entre renderizações
return <FormularioTarefa onAdicionar={adicionarTarefa} />;
}
function FormularioTarefa({ onAdicionar }) {
const [input, setInput] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
onAdicionar(input);
setInput('');
};
return (
<form onSubmit={handleSubmit}>
<input value={input} onChange={e => setInput(e.target.value)} />
<button type="submit">Adicionar</button>
</form>
);
}
useMemo
Memoriza um valor computado para otimização de performance.
import { useState, useMemo } from 'react';
function ListaFiltrada({ items }) {
const [filtro, setFiltro] = useState('');
const itemsFiltrados = useMemo(() => {
console.log('Filtrando items...');
return items.filter(item =>
item.toLowerCase().includes(filtro.toLowerCase())
);
}, [items, filtro]); // Recomputa apenas quando items ou filtro mudam
return (
<div>
<input
value={filtro}
onChange={e => setFiltro(e.target.value)}
placeholder="Filtrar..."
/>
<ul>
{itemsFiltrados.map((item, i) => <li key={i}>{item}</li>)}
</ul>
</div>
);
}
useRef
Cria uma referência mutável que persiste entre renderizações.
import { useRef, useEffect } from 'react';
function InputComFoco() {
const inputRef = useRef(null);
useEffect(() => {
// Foca no input quando o componente é montado
inputRef.current.focus();
}, []);
return <input ref={inputRef} type="text" />;
}
Para armazenar valores mutáveis:
function Cronometro() {
const [segundos, setSegundos] = useState(0);
const intervalRef = useRef(null);
const iniciar = () => {
intervalRef.current = setInterval(() => {
setSegundos(s => s + 1);
}, 1000);
};
const parar = () => {
clearInterval(intervalRef.current);
};
useEffect(() => {
return () => clearInterval(intervalRef.current);
}, []);
return (
<div>
<p>{segundos}s</p>
<button onClick={iniciar}>Iniciar</button>
<button onClick={parar}>Parar</button>
</div>
);
}
useImperativeHandle
Customiza a instância exposta ao usar ref em componentes pai.
import { useRef, useImperativeHandle, forwardRef } from 'react';
const InputCustomizado = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
scrollIntoView: () => {
inputRef.current.scrollIntoView();
},
getValue: () => {
return inputRef.current.value;
}
}));
return <input ref={inputRef} {...props} />;
});
function Formulario() {
const inputRef = useRef();
return (
<div>
<InputCustomizado ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>
Focar no Input
</button>
<button onClick={() => alert(inputRef.current.getValue())}>
Mostrar Valor
</button>
</div>
);
}
useLayoutEffect
Similar ao useEffect, mas executa sincronamente após mutações do DOM.
import { useState, useLayoutEffect, useRef } from 'react';
function TooltipPosicionado() {
const [tooltipHeight, setTooltipHeight] = useState(0);
const tooltipRef = useRef(null);
useLayoutEffect(() => {
// Lê o DOM e atualiza antes da pintura
const height = tooltipRef.current.getBoundingClientRect().height;
setTooltipHeight(height);
}, []);
return (
<div
ref={tooltipRef}
style={{ top: `-${tooltipHeight}px` }}
>
Tooltip
</div>
);
}
useDebugValue
Exibe um rótulo customizado no React DevTools.
import { useState, useDebugValue } from 'react';
function useStatusOnline() {
const [isOnline, setIsOnline] = useState(true);
// Aparece no React DevTools
useDebugValue(isOnline ? 'Online' : 'Offline');
return isOnline;
}
function Perfil() {
const isOnline = useStatusOnline();
return <div>{isOnline ? '🟢' : '🔴'} Status</div>;
}
Hooks do React 18+
useId
Gera IDs únicos e estáveis para acessibilidade.
import { useId } from 'react';
function CampoFormulario({ label }) {
const id = useId();
return (
<div>
<label htmlFor={id}>{label}</label>
<input id={id} type="text" />
</div>
);
}
useTransition
Marca atualizações de estado como transições não urgentes.
import { useState, useTransition } from 'react';
function BuscaComTransition() {
const [isPending, startTransition] = useTransition();
const [input, setInput] = useState('');
const [resultados, setResultados] = useState([]);
const handleChange = (e) => {
setInput(e.target.value);
startTransition(() => {
// Esta atualização é marcada como não urgente
const novosResultados = buscarResultados(e.target.value);
setResultados(novosResultados);
});
};
return (
<div>
<input value={input} onChange={handleChange} />
{isPending && <p>Buscando...</p>}
<ul>
{resultados.map(r => <li key={r.id}>{r.nome}</li>)}
</ul>
</div>
);
}
useDeferredValue
Adia a atualização de uma parte da UI.
import { useState, useDeferredValue, useMemo } from 'react';
function ListaComDeferredValue({ items }) {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
const resultados = useMemo(() => {
return items.filter(item =>
item.toLowerCase().includes(deferredQuery.toLowerCase())
);
}, [items, deferredQuery]);
return (
<div>
<input
value={query}
onChange={e => setQuery(e.target.value)}
/>
<ListaLenta items={resultados} />
</div>
);
}
useSyncExternalStore
Permite que componentes se inscrevam em stores externas.
import { useSyncExternalStore } from 'react';
function useWindowWidth() {
return useSyncExternalStore(
(callback) => {
window.addEventListener('resize', callback);
return () => window.removeEventListener('resize', callback);
},
() => window.innerWidth,
() => 0 // Valor no servidor
);
}
function ResponsiveComponent() {
const width = useWindowWidth();
return <div>Largura: {width}px</div>;
}
useInsertionEffect
Hook para bibliotecas CSS-in-JS injetarem estilos antes de mutações do DOM.
import { useInsertionEffect } from 'react';
function useCSS(rule) {
useInsertionEffect(() => {
// Injeta estilos antes do useLayoutEffect
const style = document.createElement('style');
style.textContent = rule;
document.head.appendChild(style);
return () => {
document.head.removeChild(style);
};
}, [rule]);
}
function ComponenteEstilizado() {
useCSS('.minha-classe { color: red; }');
return <div className="minha-classe">Texto vermelho</div>;
}
Hooks Customizados
Você pode criar seus próprios hooks combinando hooks existentes.
import { useState, useEffect } from 'react';
// Hook customizado para buscar dados
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let cancelado = false;
setLoading(true);
fetch(url)
.then(res => res.json())
.then(data => {
if (!cancelado) {
setData(data);
setLoading(false);
}
})
.catch(err => {
if (!cancelado) {
setError(err);
setLoading(false);
}
});
return () => {
cancelado = true;
};
}, [url]);
return { data, loading, error };
}
// Uso do hook customizado
function MeuComponente() {
const { data, loading, error } = useFetch('/api/usuarios');
if (loading) return <p>Carregando...</p>;
if (error) return <p>Erro: {error.message}</p>;
return <ul>{data.map(u => <li key={u.id}>{u.nome}</li>)}</ul>;
}
Regras dos Hooks
- Chame hooks apenas no nível superior - Não chame hooks dentro de loops, condições ou funções aninhadas
- Chame hooks apenas de funções React - Componentes funcionais ou hooks customizados
- Hooks customizados devem começar com "use" - Convenção para identificação
// ❌ Errado
function Componente({ condicao }) {
if (condicao) {
const [state, setState] = useState(0); // Erro!
}
}
// ✅ Correto
function Componente({ condicao }) {
const [state, setState] = useState(0);
if (condicao) {
// Use o state aqui
}
}