Como utilizar Redux no React?
Um dos maiores desafios existentes dentro do desenvolvimento front end na atualidade é como será arquitetado o gerenciamento dos estados dentro de uma aplicação. Para isto, foi criada uma biblioteca ovacionada desde sempre por sua capacidade, organização e condução de estados: o Redux. É sobre ele que iremos aprender hoje.
O que é um estado ?
É muito importante, antes de começarmos a colocar a mão na massa, entendermos o conceito de estado e para que ele serve. Imagine que você tenha uma aplicação que, ao ser realizado determinado tipo de interação (como por exemplo adicionar um item ao carrinho ou um filtro que limita o que você quer ver), seja necessário que uma determinada quantidade de informações fiquem temporariamente salvas enquanto a tela não for fechada ou atualizada. Esse lugarzinho onde estas informações ficarão armazenadas é o que chamamos de estado. Sem ele, tudo no React seria uma bagunça ou no mínimo uma dez vezes mais desgastante de ser implementado.
Redux
Agora que entendemos a importância e funcionalidade de um estado, vamos supor a situação em que temos um componente chamado Input e, dentro dele, um outro componente chamado Exibidor. O componente Input também possui um elemento de input do tipo texto que, ao digitarmos algo, o texto deve aparecer em um elemento h1 criado no componente Exibidor. Utilizaremos estados para realizar essa façanha:
Como podemos ver nas imagens acima, não há muita dificuldade em passar um estado de um componente “pai” para um componente “filho”. Basta que ele seja enviado para o componente “filho” como uma propriedade, assim como foi feito para o componente Exibidor. Todavia, a coisa fica complicada quando temos que repassar um estado para um componente que está muito distante em uma determinada hierarquia (o componente “filho” do componente “filho” do componente “filho” do componente que nós temos o estado, por exemplo), ou quando os componentes que precisam das informações de um determinado estado não tem ligação direta com o componente que o armazena. Nestes casos, ou muito trabalho repetitivo será necessário (repassando para todos os componentes a propriedade com o estado), ou sequer é possível fazê-lo (para o caso de componentes sem relacionamento hierárquico). Foi para resolver estes problemas que o Redux foi criado.
O Redux é uma biblioteca focada na missão de gerenciar estados de aplicações javascript, de forma que exista um determinado arquivo dentro do projeto que ficará responsável por guardar todos os estados que precisam ser compartilhados ou alterados por um determinado número de componentes.
Uma vez explicado o que é o Redux e para que ele serve, podemos começar com sua instalação e configuração inicial, para que tudo fique pronto para a utilização.
Instalando e configurando o Redux
Antes de mais nada, o primeiro passo (como é esperado) é criar uma aplicação React. Sendo assim, vamos nomear o nosso primeiro projeto utilizando o Redux com um nome intuitivo. Que tal project-react-redux?
npx create-react-app project-react-redux
cd project-react-redux
npm start
OBS - Foi utilizado o npm como ferramenta de gerenciamento de pacotes, mas sinta-se à vontade para utilizar o que lhe for mais confortável.
Como o objetivo deste artigo é explicar o funcionamento do redux, começaremos com uma implementação simples. Que tal fazer o mesmo exemplo anterior, só que sem relação hierárquica de “pai e filho” ?
Note que foi necessário realizar algumas alterações nos componentes. Primeiro, o componente Input agora possui um botão, que utilizaremos no futuro para enviar o estado local do componente para estado global do redux. Isto acontece porque é mais recomendado que se enviem dados já completos do que a cada pequena atualização (como é o caso de um onChange). Isso geraria uma série de renderizações que seriam desnecessárias para a aplicação. Além disso, o componente Exibidor ainda não apresenta nenhuma informação dentro do elemento h1. Isto ocorre porque ainda iremos configurá-lo de forma que ele acesse o redux e traga a informação necessária a ser exibida. O que importa neste momento é que criamos a estrutura básica que receberá a implementação do redux.
Uma vez criado o ambiente de desenvolvimento, precisamos instalar a biblioteca do Redux. Execute na pasta raíz do projeto a seguinte linha de comando no terminal:
npm install redux react-redux
Feita a instalação, agora vamos criar as três estruturas principais do redux: store, reducer e actions. Para tal é sugerido que, para fins de organização, seja criado um diretório e um arquivo index para cada item citado, conforme apresentado abaixo:
Recaptulando
Até o presente momento, criamos um projeto que contém dois componentes que terão a função de enviar (Input) e receber (Exibidor) informações para o redux. Além disso, instalamos o redux e criamos um diretório e um arquivo index para cada estrutura essencial para seu funcionamento: store, actions e reducer. Agora, iremos entender para que servem e configurar cada uma dessas estruturas.
Actions
As actions são funções que irão informar ao redux o que deve ser atualizado e como deve acontecer. Cada action destaca um objetivo que nossa aplicação precisa alcançar.
Elas sempre serão funções que retornam um objeto com, no mínimo, duas chaves:
- type - contém uma string que descreve a ação a ser realizada;
- payload - possui o dado que vem da nossa aplicação.
Trazendo estes conceitos para o exemplo que estamos utilizando, criaremos uma action chamada actionSave que possui um type igual a “REGISTRA_NOME” e um payload igual ao estado local do componente Input, que virá como parâmetro na função.
Configurando o Reducer
O reducer é responsável por receber as solicitações feitas pelas actions e atualizar o estado existente no store. É o intermédio entre o que deve ser feito e o que está armazenado.
Trata-se de uma função que recebe como parâmetros um estado e uma action. A partir destas duas informações, ela fará uma determinada atualização no estado de acordo com cada chave type de cada action que é repassada. Para isto, utilizamos um Switch que recebe a chave type e que possui um case para cada action criada. No nosso caso, temos apenas uma:
OBS - Note que foi criada uma constante chamada “INITIAL_STATE”. Este será o estado inicial da nossa aplicação e, caso o estado (denotado como o parâmetro state) esteja vazio, utilizaremos o estado inicial que criamos ao invés dele. Além disso é possível verificar que, como foi dito, há um case criado para o type da actionSave. Neste caso, a ação é salvar no estado o texto enviado.
Em outras palavras, informamos ao reducer que sempre que ele receber como um parâmetro uma action com a chave type igual a “REGISTRA_NOME”, ele deve salvar no estado a informação que está salva na chave payload.
Store
O Store é o ponto da aplicação onde ficarão armazenados os estados que nós iremos utilizar. Por meio dele, iremos salvar e resgatar as informações dos estados e repassar para qualquer componente que desejarmos (com as devidas configurações, óbvio).
Para criar um store, utilizamos a função nativa do redux createStore. Esta função pode receber mais de um parâmetro para auxiliar na implementação, mas para fins de aprendizado (e para não confundir muito sua cabeça) utilizaremos apenas o único parâmetro que é obrigatório: o reducer, criado no passo anterior.
Recaptulando
Nos últimos passos, configuramos a estrutura principal do redux: criamos uma action que define como e o que deve ser atualizado no estado global da aplicação, um reducer que executa a action e, por fim, um store que é o local onde é armazenado este estado por meio do reducer.
Como a aplicação se comunica com o Redux?
Se você prestou muita atenção até aqui, deve ter percebido que nossos componentes Input e Exibidor ainda não possuem nenhuma conexão com nossas actions, reducer e store. Este é o último passo faltante para concluirmos a implementação do redux e, para isto, utilizaremos o componente Provider e os hooks useDispatch e useSelector.
Provider
O Provider é o componente que irá dizer para a nossa aplicação que temos um estado global criado com o Redux e que ele está disponível para ser acessado. Para isto, este componente deve ser importado do “react-redux” e deve encapsular toda a parte do nosso projeto que terá o acesso ao redux. No nosso caso, como nossa implementação está no componente App, iremos encapsula-lo com o Provider.
IMPORTANTE - O Provider é um componente que deve possuir uma propriedade chamada store, onde enviaremos como valor o store que nós construímos para o redux. Veja:
UseSelector e UseDispatch
Para ter acesso ao estado global gerado com o redux, utilizamos os dois hooks já citados. Enquanto o useSelector é utilizado para a leitura do estado global, o useDispatch é utilizado para atualização do mesmo.
Importamos o useSelector do ‘react-redux’ e atribuímos ele a uma constante que, neste exemplo, chamaremos de globalState. O useSelector recebe uma função como parâmetro que recebe o estado global do redux. Desta forma, basta retornar este mesmo estado que teremos acesso ao que precisamos:
Já o useDispatch é uma função que dispara para o reducer uma action. Desta forma, também devemos criar uma constante que receberá o useDispatch. Esta por sua vez será utilizada para enviar atualizações para o estado global e, no nosso caso, enviaremos como parâmetro a actionSave que criamos:
E voilà! Está pronta nossa aplicação com redux!
Considerações finais
Como é de se esperar, o ato de programar requer prática e muita repetição. Para o redux não é diferente. Pode até parecer um pouco complexo de se implementar à primeira vista, mas sua existência abre portas e facilita implementações de uma forma indescritível, sem contar que o mercado de trabalho o utiliza com frequência. Vale a pena acreditar no redux também.