⚛Os 10 React Hooks Mais Úteis: 05 - useReducer⚛
Tags: react, javascript, webdev, beginners
Published: 2022-12-28 20:41:27

_Este é o quinto artigo de uma série de 10, que explica de forma simplificada e com exemplos, os react hooks mais utilizados em programação._

---

O `useReducer` é um hook do React que permite **gerenciar o estado** de um componente de forma semelhante ao reducer do [Redux](https://www.geeksforgeeks.org/introduction-to-react-redux/).

O `useReducer` é útil quando você precisa gerenciar um [estado](https://medium.com/edonec/state-in-react-an-overview-a182675cee2c) **mais complexo** ou compartilhado por vários componentes em sua aplicação. Ele também pode ser uma alternativa mais eficiente ao `useState` em casos em que o estado depende de valores anteriores, pois o `useReducer` **só requer que você forneça o próximo estado**, em vez de todo o estado atual. 

O primeiro parâmetro do `useReducer` é o reducer, que é uma função que recebe o [estado](https://medium.com/edonec/state-in-react-an-overview-a182675cee2c) atual e uma ação como entrada e retorna o próximo estado. O reducer é responsável por atualizar o estado de acordo com a ação fornecida. Ele é geralmente escrito como um _switch statement_ que verifica o tipo da ação e retorna o próximo estado de acordo com a ação correspondente. 

O segundo parâmetro do `useReducer` é o estado inicial, que é o valor inicial do estado do componente. Ele é passado como o primeiro argumento para o reducer quando o componente é montado pela primeira vez. Ao chamar o `useReducer`, o hook retorna um par de valores: **o estado atual** e a **função de dispatch**. O estado atual é o valor atual do estado do componente, que é atualizado pelo reducer sempre que uma ação é despachada. A função de dispatch é usada para despachar uma ação para o reducer, o que atualiza o estado do componente.
<br>
# Empregos do useReducer
Entenda o funcionamento do react hook `useReducer` com os exemplos abaixo.

## 1. Contador com useReducer
Acompanhe abaixo no arquivo `Files>src>App.jsx` o exemplo de um contador simples sobre o uso desse hook:

{% embed https://replit.com/@MarceloPetry/useReducer-Counter?v=1 %}

1 - `import { useReducer } from "react"`: este comando importa o hook `useReducer` do módulo `react`. 
2 - `function reducer(state, action)`: esta é uma função chamada reducer, que recebe dois argumentos: `state` e `action`. 
3 - `switch (action.type)`: neste trecho, o valor do atributo `type` da ação é usado para escolher qual ação será realizada. 
4 - `case "increment"`: se o valor do atributo `type` da ação for "increment", será executado o código abaixo deste case. 
5 - `return { count: state.count + 1 }`: este comando retorna um novo objeto com o valor de `count` incrementado em 1 em relação ao valor atual. 
6 - `case "decrement"`: se o valor do atributo `type` da ação for "decrement", será executado o código abaixo deste case. 
7 - `return { count: state.count - 1 }`: este comando retorna um novo objeto com o valor de `count` decrementado em 1 em relação ao valor atual. 
8 - `default`: se o valor do atributo `type` da ação não for reconhecido pelos cases acima, será executado o código abaixo deste default. 
9 - `throw new Error()`: este comando lança uma exceção, interrompendo a execução do código. 
10 - `function Counter()`: esta é uma função que retorna um componente do React. 
11 - `const [state, dispatch] = useReducer(reducer, { count: 0 })`: este comando usa o hook `useReducer` para gerenciar o estado do componente. O primeiro argumento é o reducer definido anteriormente, e o segundo é o estado inicial, um objeto com o valor de `count` igual a 0. O `useReducer` retorna um array com dois elementos: o primeiro é o estado atual, e o segundo é uma função chamada `dispatch`, que permite disparar uma ação para o reducer. 
12 - ` dispatch({ type: "increment" })}>+`: este é um botão que, quando clicado, dispara uma ação de tipo "increment" para o reducer usando a função `dispatch`.
13 - ` dispatch({ type: "decrement" })}>-`: este é um botão que, quando clicado, dispara uma ação de tipo "decrement" para o reducer usando a função `dispatch`.
<br>
## 2. Hook useReducer aplicado à lista de tarefas
No exemplo abaixo, o componente `Files>src>App.jsx` exibe uma lista de tarefas, um formulário para adicionar novas tarefas e botões para marcar tarefas como concluídas ou removê-las. Acompanhe:

{% embed https://replit.com/@MarceloPetry/useReducer-Tasks-List?v=1 %}

1 - `React` e `useReducer` são importados do pacote `react`.
2 - `initialState` é uma constante que armazena um array vazio, que será o estado inicial do componente. 
3 - `reducer` é uma função que recebe o estado atual e uma ação como argumentos e retorna um novo estado. Ela possui um switch case com três casos possíveis, correspondentes às ações "ADD_TASK", "TOGGLE_TASK" e "REMOVE_TASK". 
4 - `TaskList` é uma função que retorna um componente React. Ela utiliza o hook `useReducer` para gerenciar o estado do componente, passando como primeiro argumento a função `reducer` e como segundo argumento o estado inicial, armazenado na constante `initialState`.
5 - `handleSubmit` é uma função que é chamada quando o formulário é submetido. Ela previne o comportamento padrão de recarregar a página e envia uma ação do tipo "ADD_TASK" com o texto digitado no campo de input como payload. Ela também limpa o campo de input. 
6 - `handleToggleTask` é uma função que é chamada quando o checkbox de uma tarefa é clicado. Ela envia uma ação do tipo "TOGGLE_TASK" com o id da tarefa como payload. 
7 - `handleRemoveTask` é uma função que é chamada quando o botão "Remove" de uma tarefa é clicado. Ela envia uma ação do tipo "REMOVE_TASK" com o id da tarefa como payload. 
8 - O componente é retornado com um formulário para adicionar uma nova tarefa, uma lista de tarefas e, para cada tarefa, um checkbox para marcar como concluída e um botão para remover. Cada tarefa possui o texto da descrição e o id como chave única. 
9 - O componente é exportado para que possa ser utilizado em outros arquivos.
<br>
## 3. Hook useReducer em Formulário de Nome/E-mail

Outro exemplo para compreendermos o `useReducer` é no caso em que precisamos manipular os dados de um formulário em nosso aplicativo. O reducer define o que acontece com o estado quando as ações são emitidas e usamos o gancho para controlar o estado inicial. Depois, temos campos de entrada que emitem ações para o nosso reducer e um botão de redefinição para redefinir os dados do formulário. Veja em `Files>src>App.jsx`:

{% embed https://replit.com/@MarceloPetry/MailandName-Form-useReducer?v=1 %}

1 - `import React, { useReducer } from 'react';`: Essa linha importa o React e o hook `useReducer` do pacote react. 
2 - `const initialState = { formData: { name: '', email: '' } };`: Essa constante define o estado inicial do componente como um objeto que contém um objeto aninhado chamado `formData`, que, por sua vez, contém os campos de formulário `name` e `email` inicializados como strings vazias. 
3 - `function reducer(state, action) { ... }`: Essa função é o reducer que será usado pelo hook `useReducer`. Ele recebe dois argumentos: o estado atual e uma ação. A função verifica o tipo de ação e, em seguida, retorna um novo estado de acordo. 
4 - `const [state, dispatch] = useReducer(reducer, initialState);`: Essa linha usa o hook `useReducer` para gerenciar o estado do componente. Ela recebe dois argumentos: o reducer e o estado inicial. Em seguida, ela desestrutura o valor retornado pelo hook em duas variáveis: o estado atual e uma função chamada `dispatch`, que pode ser usada para enviar ações para o reducer. 
5 - `const handleUpdateFormData = formData => dispatch({ type: 'UPDATE_FORM_DATA', formData });`: Essa função é um manipulador de eventos que é chamado quando os campos de formulário são alterados. Ele recebe um objeto `formData` como argumento e usa a função `dispatch` para enviar uma ação do tipo `UPDATE_FORM_DATA` para o reducer, passando o objeto `formData` como um segundo argumento.
6 - `const handleResetFormData = () => dispatch({ type: 'RESET_FORM_DATA'});`: Essa função é um manipulador de eventos que é chamado quando o botão "Reset" é clicado. Ele usa a função `dispatch` para enviar uma ação do tipo `RESET_FORM_DATA` para o reducer.
7 - `<form>`: Essa é a tag principal do formulário.
8 - `<input type="text" name="name" value={state.formData.name} placeholder="Enter Your Name" onChange={e => handleUpdateFormData({[e.target.name]: e.target.value })} />`: Essa é uma entrada de texto para o campo de nome. Ela recebe o valor atual do campo de nome doestado através da propriedade `value`, e usa o manipulador de eventos `handleUpdateFormData` para atualizar o estado quando o campo é alterado.
9 - ` handleUpdateFormData({ [e.target.name]: e.target.value })} />`: este é um elemento de entrada HTML que representa um campo de formulário para o usuário inserir o endereço de e-mail. Quando o usuário digita um valor no campo, a função `handleUpdateFormData` é chamada para atualizar os dados do formulário. 
10 - `Reset`: este é um elemento de botão HTML que tem um evento `onClick` que chama a função `handleResetFormData` quando o botão é clicado. Isso faz com que os dados do formulário sejam redefinidos para seus valores iniciais. 
11 - `export default App;`: este código exporta o componente `App` para que ele possa ser usado em outros arquivos.
<br>
## 4. Formulário de busca com useReducer

Neste exemplo, testaremos o hook `useReducer` em um componente de formulário de busca. Acompanhe pelo `Files>src>App.jsx`:

{% embed https://replit.com/@MarceloPetry/Search-Form-useReducer?v=1 %}

1 - `import React, { useReducer } from 'react';`: Importa o módulo `react` e a função `useReducer` do módulo `react`. 
2 - `import './App.css'`: Importa o arquivo de estilos `App.css` para o componente `App`. 
3 - `const initialState = { query: '', results: [] };`: Define o estado inicial do componente `App`, contendo um objeto com as propriedades `query` e `results`. A propriedade `query` armazena a string de pesquisa atual, enquanto a propriedade `results` armazena os resultados da pesquisa. 
4 - `const reducer = (state, action) => {...}`: Define uma função reducer que recebe um estado atual e uma ação e retorna um novo estado. A função reducer é usada pelo `useReducer` para atualizar o estado do componente. 
5 - `const App = () => {...}`: Define o componente `App` como uma função. 
6 - `const [state, dispatch] = useReducer(reducer, initialState);`: Chama a função `useReducer` passando a função reducer e o estado inicial como argumentos. A função `useReducer` retorna um array com o estado atual e uma função `dispatch` que pode ser usada para disparar ações para a função reducer. O estado atual é armazenado na variável `state`, enquanto a função `dispatch` é armazenada na variável `dispatch`.
7 - `const handleInputChange = e => {...};`: Define uma função `handleInputChange` que é chamada toda vez que o usuário altera o valor do input de pesquisa. A função dispara uma ação `UPDATE_QUERY` para a função reducer, passando o valor atual do input como argumento.
8 - `const handleSearch = () => {...};`: Define uma função `handleSearch` que é chamada toda vez que o usuário clica no botão "Search". A função simula uma chamada a uma API, gerando alguns resultados de pesquisa fictícios e disparando uma ação `UPDATE_RESULTS` para a função reducer, passando os resultados como argumento. 
9 - `const handleReset = () => {...};`: Define uma função `handleReset` que é chamada toda vez que o usuário clica no botão "Reset". A função dispara uma ação `RESET` para a função reducer, reinicializando o estado do componente para o estado inicial. 
10 - `return (...)`: Retorna o elemento JSX que representa o componente `App`. O elemento inclui um input de texto que exibe o valor da propriedade `query` do estado atual e chama a função `handleInputChange` toda vez que o valor é alterado. Também inclui dois botões que chamam as funções `handleSearch` e `handleReset` quando clicados. Por fim, o elemento inclui um conjunto de elementos `div` que exibem os resultados da pesquisa armazenados na propriedade `results` do estado atual.

---

# Conclusão

O `useReducer` é um hook do React que permite que um componente gerencie seu próprio estado de maneira semelhante ao padrão reducer de uma aplicação Redux. 

Ao invés de armazenar o estado diretamente no componente, o estado é armazenado em uma função `reducer`, que toma o estado atual e uma ação como argumentos e retorna o próximo estado da aplicação. Isso permite que a lógica de atualização do estado seja centralizada e **facilita o gerenciamento de mudanças de estado complexas** em componentes. 

Além disso, o uso do `useReducer` pode tornar o código mais legível, pois a lógica de atualização do estado é isolada em uma única função, em vez de espalhada por todo o componente. 

No entanto, é importante lembrar de que o `useReducer` não é a solução ideal para todos os casos e deve ser usado com moderação, considerando as necessidades específicas da sua aplicação.

---

[marcelopetry.com](https://marcelopetry.com)