Skip to main content

useReducer

O hook useReducer é uma alternativa ao useState, especialmente útil quando o gerenciamento de estado se torna mais complexo. Ele é baseado no conceito de reducers, muito parecido com o que usamos no Redux.

Enquanto o useState é mais simples para estados isolados, o useReducer brilha quando precisamos gerenciar múltiplas transições de estado ou quando as mudanças dependem do estado anterior de uma maneira mais controlada.

Ele é altamente recomendado para evitar a criação de vários hooks com useState, o que pode poluir a página e disparar de forma demasiada re-renders na aplicação. Abaixo trago um exemplo de uso:

Live Editor
import { userReducer } from 'react';
// Estado inicial para configuração e controle do chat
const initialState = {
  message: '',
  chatHistory: [],
  modelConfig: {
    temperature: 0.7,
    top_k: 50,
    top_p: 0.9,
    max_tokens: 200,
    threshold: 0.5,
  },
}

// Função reducer para gerenciar as ações do chat e das configurações do modelo
function reducer(state, action) {
  switch (action.type) {
    case 'SEND_MESSAGE':
      return {
        ...state,
        chatHistory: [...state.chatHistory, { user: 'Você', message: state.message }],
        message: '',
      }
    case 'UPDATE_MESSAGE':
      return { ...state, message: action.payload }
    case 'UPDATE_CONFIG':
      return {
        ...state,
        modelConfig: { ...state.modelConfig, [action.key]: action.value },
      }
    case 'CLEAR_CHAT':
      return { ...state, chatHistory: [] }
    default:
      throw new Error('Ação não reconhecida')
  }
}

function AIChatComponent() {
  const [state, dispatch] = useReducer(reducer, initialState)

  return (
    <div>
      <h2>Chat com IA</h2>
      
      <div>
        <h3>Histórico</h3>
        <ul>
          {state.chatHistory.map((chat, index) => (
            <li key={index}>
              <strong>{chat.user}:</strong> {chat.message}
            </li>
          ))}
        </ul>
      </div>

      <div>
        <h3>Mensagem</h3>
        <textarea
          value={state.message}
          onChange={(e) => dispatch({ type: 'UPDATE_MESSAGE', payload: e.target.value })}
          placeholder="Digite sua mensagem..."
        />
        <button onClick={() => dispatch({ type: 'SEND_MESSAGE' })}>Enviar</button>
        <button onClick={() => dispatch({ type: 'CLEAR_CHAT' })}>Limpar Chat</button>
      </div>

      <div>
        <h3>Configurações do Modelo</h3>
        <label>
          Temperature:
          <input
            type="number"
            value={state.modelConfig.temperature}
            step="0.1"
            min="0"
            max="1"
            onChange={(e) => dispatch({ type: 'UPDATE_CONFIG', key: 'temperature', value: parseFloat(e.target.value) })}
          />
        </label>

        <label>
          Top K:
          <input
            type="number"
            value={state.modelConfig.top_k}
            min="1"
            onChange={(e) => dispatch({ type: 'UPDATE_CONFIG', key: 'top_k', value: parseInt(e.target.value) })}
          />
        </label>

        <label>
          Top P:
          <input
            type="number"
            value={state.modelConfig.top_p}
            step="0.05"
            min="0"
            max="1"
            onChange={(e) => dispatch({ type: 'UPDATE_CONFIG', key: 'top_p', value: parseFloat(e.target.value) })}
          />
        </label>

        <label>
          Max Tokens:
          <input
            type="number"
            value={state.modelConfig.max_tokens}
            min="1"
            onChange={(e) => dispatch({ type: 'UPDATE_CONFIG', key: 'max_tokens', value: parseInt(e.target.value) })}
          />
        </label>

        <label>
          Threshold:
          <input
            type="number"
            value={state.modelConfig.threshold}
            step="0.05"
            min="0"
            max="1"
            onChange={(e) => dispatch({ type: 'UPDATE_CONFIG', key: 'threshold', value: parseFloat(e.target.value) })}
          />
        </label>
      </div>
    </div>
  )
}

// ESSA LINHA É UTILIZADA APENAS PARA O LIVE EDITOR; NÃO FAZ PARTE DO EXEMPLO ACIMA;
render(AIChatComponent);
Result
Loading...

Como funciona?

O useReducer aceita dois parâmetros principais:

  1. Reducer function: Função pura que recebe o estado atual e a ação, e retorna o novo estado.
  2. Estado inicial: Valor inicial do estado, que pode ser qualquer tipo de dado — objeto, array, primitivo, etc.

A função reducer geralmente usa um switch para decidir qual transformação aplicar no estado com base no tipo da ação recebida.

Depois, o useReducer retorna um array com duas posições:

  • state: O estado atual.
  • dispatch: Função que dispara uma ação para atualizar o estado.

Formação

A estrutura básica é:

const [state, dispatch] = useReducer(reducer, initialState)

Por que usar useReducer?

Se você percebe que está acumulando muitos useState, ou que precisa de lógica complexa para determinar como o estado deve mudar, o useReducer é uma escolha natural. Ele te dá mais controle, mantém a lógica de atualização centralizada e facilita a manutenção.

Dica

O useReducer é especialmente útil quando combinado com Context API para criar uma solução de gerenciamento de estado global, eliminando a necessidade de bibliotecas externas, dependendo da complexidade do projeto.

tip

Conheça mais sobre os hooks em:

Referências: