Os hooks revolucionaram o desenvolvimento React ao permitir que componentes funcionais gerenciem estado, efeitos colaterais e lógica complexa de forma elegante. Com o React 19, novos hooks foram introduzidos para otimizar ainda mais o fluxo de trabalho. Neste artigo, exploraremos hooks clássicos, avançados e as novidades da versão 19 com exemplos práticos.
Hooks Básicos do React
useState: Gerenciamento Simples de Estado
Gerencia estados locais em componentes funcionais. Ideal para valores que mudam ao longo do tempo.
Exemplo: Contador Interativo
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Você clicou {count} vezes</p>
<button onClick={() => setCount(count + 1)}>
Incrementar
</button>
</div>
);
}
useEffect: Efeitos Colaterais
Executa código após renderização, como chamadas de API ou manipulação do DOM.
Exemplo: Buscando Dados de uma API
import { useState, useEffect } from 'react';
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch('https://api.example.com/users')
.then(response => response.json())
.then(data => setUsers(data));
}, []); // Executa apenas uma vez
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
useContext: Compartilhamento de Estado Global
Acessa valores de contexto sem prop drilling.
Exemplo: Tema Escuro/Claro
import { createContext, useContext, useState } from 'react';
const ThemeContext = createContext();
function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Alternar para tema {theme === 'light' ? 'escuro' : 'claro'}
</button>
);
}
useRef: Referências Mutáveis
Armazena valores que persistem entre renderizações sem causar re-render.
Exemplo: Foco em Input
import { useRef } from 'react';
function TextInput() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>Focar no Input</button>
</div>
);
}
Hooks Avançados e Customizados
useReducer: Estado Complexo
Gerencia estados com lógica mais elaborada, similar ao Redux.
Exemplo: Lista de Tarefas
import { useReducer } from 'react';
function todosReducer(state, action) {
switch (action.type) {
case 'ADD_TODO':
return [...state, { text: action.text, completed: false }];
case 'TOGGLE_TODO':
return state.map((todo, index) =>
index === action.index ? { ...todo, completed: !todo.completed } : todo
);
default:
return state;
}
}
function TodoApp() {
const [todos, dispatch] = useReducer(todosReducer, []);
const handleSubmit = (e) => {
e.preventDefault();
dispatch({ type: 'ADD_TODO', text: e.target.elements.todo.value });
e.target.reset();
};
return (
<div>
<form onSubmit={handleSubmit}>
<input name="todo" />
<button type="submit">Adicionar</button>
</form>
{todos.map((todo, index) => (
<div
key={index}
onClick={() => dispatch({ type: 'TOGGLE_TODO', index })}
style={ textDecoration: todo.completed ? 'line-through' : 'none' }
>
{todo.text}
</div>
))}
</div>
);
}
useMemo e useCallback: Otimização de Performance
- useMemo: Memoriza valores calculados.
- useCallback: Memoriza funções.
Exemplo: Cálculo Pesado
import { useMemo, useState } from 'react';
function ExpensiveComponent({ list }) {
const sortedList = useMemo(() => {
console.log('Ordenando lista...');
return [...list].sort();
}, [list]);
return <div>{sortedList.join(', ')}</div>;
}
Custom Hooks: Reutilização de Lógica
Exemplo: useFetch para Requisições HTTP
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(data => {
setData(data);
setLoading(false);
});
}, [url]);
return { data, loading };
}
// Uso no componente:
function UserProfile({ userId }) {
const { data: user, loading } = useFetch(`https://api.example.com/users/${userId}`);
if (loading) return <div>Carregando...</div>;
return <div>{user.name}</div>;
}
Novos Hooks do React 19
useOptimistic: Atualizações Otimistas
Atualiza a UI antes da confirmação do servidor, revertendo em caso de falha.
Exemplo: Adição Otimista de Comentário
import { useOptimistic } from 'react';
function CommentForm({ onSubmit }) {
const [optimisticComments, addOptimisticComment] = useOptimistic(
[],
(state, newComment) => [...state, { text: newComment, sending: true }]
);
const handleSubmit = async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const comment = formData.get('comment');
addOptimisticComment(comment);
try {
await onSubmit(comment);
} catch (error) {
// Reverte a UI se a requisição falhar
}
};
return (
<div>
<form onSubmit={handleSubmit}>
<input name="comment" />
<button type="submit">Enviar</button>
</form>
{optimisticComments.map((comment, index) => (
<div style={{ opacity: comment.sending ? 0.5 : 1 }}>
{comment.text}
</div>
))}
</div>
);
}
useResource: Integração com Suspense
Gerencia dados assíncronos de forma declarativa.
Exemplo: Carregamento de Dados com Fallback
import { useResource, Suspense } from 'react';
function fetchUser(id) {
// Retorna uma promise
}
function UserProfile({ userId }) {
const userResource = useResource(() => fetchUser(userId));
return <div>{userResource.read().name}</div>;
}
// Uso no componente pai:
<Suspense fallback={<div>Carregando usuário...</div>}>
<UserProfile userId={1} />
</Suspense>
useEventListener: Ouvintes de Eventos Simplificados
Gerencia listeners de eventos de forma limpa.
Exemplo: Monitorar Tamanho da Janela
import { useEventListener } from 'react';
function WindowSize() {
const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight });
useEventListener('resize', () => {
setSize({ width: window.innerWidth, height: window.innerHeight });
});
return <div>Tamanho da janela: {size.width}x{size.height}</div>;
}
useMediaQuery: Design Responsivo
Reage a mudanças em media queries.
Exemplo: Tema Escuro com Preferência do Sistema
import { useMediaQuery } from 'react';
function DarkModeToggle() {
const prefersDark = useMediaQuery('(prefers-color-scheme: dark)');
const [isDark, setIsDark] = useState(prefersDark);
// Atualiza o tema do site aqui...
return (
<button onClick={() => setIsDark(!isDark)}>
{isDark ? 'Desativar modo escuro' : 'Ativar modo escuro'}
</button>
);
}
useErrorBoundary: Tratamento Elegante de Erros
Captura erros em componentes filhos.
Exemplo: Limite de Erro Customizado
import { useErrorBoundary } from 'react';
function ErrorProneComponent() {
const { ErrorBoundary, didCatch, error } = useErrorBoundary();
return didCatch ? (
<div>Ocorreu um erro: {error.message}</div>
) : (
<ErrorBoundary>
<ComponenteQuePodeFalhar />
</ErrorBoundary>
);
}
Conclusão
Os hooks do React continuam a evoluir, trazendo ferramentas poderosas para simplificar o desenvolvimento. Com o React 19, recursos como useOptimistic e useResource elevam a experiência do usuário ao lidar com operações assíncronas de forma fluida, enquanto hooks como useMediaQuery e useEventListener facilitam a criação de interfaces adaptativas.
Ao dominar esses hooks — desde os básicos até os mais recentes — você estará equipado para construir aplicações mais robustas, performáticas e fáceis de manter. Experimente integrar essas técnicas em seus projetos e veja como elas transformam seu fluxo de trabalho! 🚀