<h2>useReducer: Gerenciamento de Estado Complexo</h2>
<p>O <code>useReducer</code> é o hook ideal quando seu estado tem múltiplas sub-valores ou a lógica de atualização é complexa. Diferente do <code>useState</code>, ele utiliza um padrão reducer similar ao Redux, onde ações disparadas modificam o estado de forma previsível.</p>
<p>A estrutura consiste em três elementos: o estado atual, uma função reducer que processa ações, e a função dispatch para dispará-las. Considere um carrinho de compras onde você precisa adicionar produtos, remover e limpar o carrinho simultaneamente:</p>
<pre><code class="language-javascript">import React, { useReducer } from 'react';
const initialState = { items: [], total: 0 };
function cartReducer(state, action) {
switch(action.type) {
case 'ADD_ITEM':
return {
items: [...state.items, action.payload],
total: state.total + action.payload.price
};
case 'REMOVE_ITEM':
return {
items: state.items.filter((_, i) => i !== action.payload),
total: state.total - state.items[action.payload].price
};
case 'CLEAR':
return initialState;
default:
return state;
}
}
function ShoppingCart() {
const [cart, dispatch] = useReducer(cartReducer, initialState);
return (
<div>
<button onClick={() => dispatch({
type: 'ADD_ITEM',
payload: { name: 'Produto', price: 50 }
})}>
Adicionar Item
</button>
<p>Total: R$ {cart.total}</p>
</div>
);
}</code></pre>
<p>Essa abordagem torna o código mais previsível e facilita testes, especialmente em aplicações com lógica complexa.</p>
<h2>useContext: Compartilhamento de Estado Global</h2>
<p>O <code>useContext</code> elimina a necessidade de prop drilling ao criar um canal direto de comunicação entre componentes distantes na árvore. Combinado com <code>useReducer</code>, cria um sistema robusto de gerenciamento de estado.</p>
<p>A implementação envolve criar um Context, um Provider que envolve a aplicação, e consumidores que acessam os valores. Veja um exemplo prático com tema da aplicação:</p>
<pre><code class="language-javascript">import React, { createContext, useContext, useReducer } from 'react';
const ThemeContext = createContext();
function themeReducer(state, action) {
switch(action.type) {
case 'TOGGLE_THEME':
return { ...state, isDark: !state.isDark };
case 'SET_COLOR':
return { ...state, primaryColor: action.payload };
default:
return state;
}
}
function ThemeProvider({ children }) {
const [theme, dispatch] = useReducer(themeReducer, {
isDark: false,
primaryColor: '#3498db'
});
return (
<ThemeContext.Provider value={{ theme, dispatch }}>
{children}
</ThemeContext.Provider>
);
}
function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme deve ser usado dentro de ThemeProvider');
}
return context;
}
function Header() {
const { theme, dispatch } = useTheme();
return (
<header style={{
background: theme.isDark ? '#000' : '#fff',
color: theme.primaryColor
}}>
<button onClick={() => dispatch({ type: 'TOGGLE_THEME' })}>
{theme.isDark ? '☀️' : '🌙'}
</button>
</header>
);
}</code></pre>
<p>Este padrão é especialmente útil para contextos que precisam ser acessados em múltiplos níveis sem passar props explicitamente.</p>
<h2>useImperativeHandle: Expondo Métodos de Componentes</h2>
<p>O <code>useImperativeHandle</code> permite que componentes filhos exponham métodos imperativos que podem ser chamados pelo pai através de refs. Use com moderação, pois quebra o padrão declarativo do React, mas é essencial para integrações com bibliotecas externas.</p>
<p>Considere um formulário onde o pai precisa resetar os dados programaticamente:</p>
<pre><code class="language-javascript">import React, { useRef, useImperativeHandle, forwardRef, useState } from 'react';
const Form = forwardRef(function Form(props, ref) {
const [formData, setFormData] = useState({ name: '', email: '' });
useImperativeHandle(ref, () => ({
reset: () => setFormData({ name: '', email: '' }),
getData: () => formData,
setData: (data) => setFormData(data)
}), [formData]);
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
return (
<form>
<input
name="name"
value={formData.name}
onChange={handleChange}
placeholder="Nome"
/>
<input
name="email"
value={formData.email}
onChange={handleChange}
placeholder="Email"
/>
</form>
);
});
function App() {
const formRef = useRef();
return (
<div>
<Form ref={formRef} />
<button onClick={() => formRef.current.reset()}>
Limpar Formulário
</button>
</div>
);
}</code></pre>
<p>Utilize este hook quando precisar controlar imperativamentebehaviors específicos como validação, envio de dados ou interação com APIs externas.</p>
<h2>Combinando os Três Hooks em Prática</h2>
<p>Integrar os três hooks em uma única solução oferece máxima flexibilidade. Um sistema de notificações globais exemplifica perfeitamente:</p>
<pre><code class="language-javascript">const NotificationContext = createContext();
function notificationReducer(state, action) {
switch(action.type) {
case 'ADD':
return [...state, { id: Date.now(), ...action.payload }];
case 'REMOVE':
return state.filter(n => n.id !== action.payload);
default:
return state;
}
}
function NotificationProvider({ children }) {
const [notifications, dispatch] = useReducer(notificationReducer, []);
const notificationRef = useRef();
useImperativeHandle(notificationRef, () => ({
add: (message, type = 'info') =>
dispatch({ type: 'ADD', payload: { message, type } })
}), []);
return (
<NotificationContext.Provider value={{ notifications, dispatch, notificationRef }}>
{children}
</NotificationContext.Provider>
);
}</code></pre>
<p>Esta combinação criar sistemas escaláveis que mantêm código limpo e testável.</p>
<h2>Conclusão</h2>
<p>Dominando <code>useReducer</code>, <code>useContext</code> e <code>useImperativeHandle</code>, você terá ferramentas suficientes para gerenciar estado complexo, compartilhá-lo globalmente e integrar comportamentos imperativos quando necessário. O segredo é escolher a ferramenta certa para cada situação: use <code>useReducer</code> para lógica complexa, <code>useContext</code> para compartilhamento entre componentes distantes, e <code>useImperativeHandle</code> apenas quando o padrão declarativo não for suficiente. Pratique combinando-os em pequenos projetos para internalizar esses conceitos.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://react.dev/reference/react/useReducer" target="_blank" rel="noopener noreferrer">React Hooks Documentation - useReducer</a></li>
<li><a href="https://react.dev/reference/react/useContext" target="_blank" rel="noopener noreferrer">React Hooks Documentation - useContext</a></li>
<li><a href="https://react.dev/reference/react/useImperativeHandle" target="_blank" rel="noopener noreferrer">React Hooks Documentation - useImperativeHandle</a></li>
<li><a href="https://epicreact.dev/" target="_blank" rel="noopener noreferrer">Advanced React Patterns - Kent C. Dodds</a></li>
<li><a href="https://react.dev/reference/react/hooks" target="_blank" rel="noopener noreferrer">React Official Blog - Hooks Introduction</a></li>
</ul>