Vamos falar um pouco sobre o que é o Redux, e o problema que ele veio resolver, abordando alguns dos seus conceitos centrais.
O principal objetivo é dar um norte para aqueles que estão começando com o Redux. Por isso, neste artigo, a aplicação do Redux nos códigos exemplificadores será simples.
A par da teoria, vamos à prática, onde teremos uma exemplificação da utilização geral do Redux para gerenciamento e compartilhamento dos estados da aplicação.
Primeiramente, um requisito importante é que você tenha conhecimentos básicos do ReactJs, uma biblioteca com cara de framework popular na comunidade dev (e que eu particularmente gosto muito).
E ainda, no final, deixarei um projeto TODOLIST com aplicação do Redux o com conceitos um pouco mais avançados prontinho para você baixar e executar na sua máquina.
Quer mais? Farei algumas recomendações de cursos para você aprofundar e dominar de vez essa library tão importante.
O que é o Redux?
Redux é um container para controle e gerenciamento de estado global de aplicações JavaScript baseado na arquitetura Flux (tem o propósito de solucionar o problema de compartilhamento de estados entre componentes, tornando-o unidirecional).
Entenda a Arquitetura Flux com React
Ele foi criado em 2015 por Dan Abramov e Andrew Clark, visando resolver o problema de compartilhamento e desencadeamento de eventos entre os componentes da sua aplicação.
Redux é uma solução para compartilhamento de estados entre vários componentes diferentes, tornando isso muito fácil, previsível e rápido.
Bastante comum sua utilização com o React, uma biblioteca muito popular (ou framework, ainda existe uma discussão sobre isso) para construção de interfaces, uma vez que essa biblioteca foi criada pensando no ReactJs, mas pode ser utilizada com Angular e Vue também.
Uma aplicação sem o Redux é obrigada a desencadear eventos entre vários componentes, tornando-os fortemente acoplados, isso dificulta a manutenção do projeto, uma vez que um componente pode depender de diversos outros para funcionar.
A imagem abaixo ilustra bem o problema e a solução que o redux oferece.
Simples, não? Agora vamos aos conceitos.
Conceitos Centrais do Redux
O redux possui três conceitos centrais: store, reducers e actions.
Store
É um container imutável, isto é, não há alteração dele, e sim evolução, que armazena e centraliza o estado global da aplicação. Com isso, podemos dizer que é o conjunto de estados da aplicação centralizados/reunidos em um apenas um lugar.
O Store segue um dos princípios que formam e definem o conceito do Redux: Um único ponto de verdade.
Os outros são:
Imutabilidade do estado: o estado da aplicação é inalterável, mas é evoluível.
Alterações são realizadas apenas por funções puras: reducers recebem as actions emitidas aplicando-as ao estado global. Sempre retornando um estado.
Tecnicamente, é um objeto JavaScript que possui todos os estados dos componentes da aplicação. Além disso, a store possui a função de monitorar as mudanças e notificar os que precisam saber delas.
Reducers
Reducers são funções puras (funções que não geram efeitos colaterais, isto é, para a mesma entrada, temos a mesma saída) com a capacidade de disparar eventos e que podem alterar um atributo da store, evoluindo o estado global da aplicação.
Funcionam como filtros recebendo e tratando as informações, enviando essas informações à store. É encarregado de lidar com todas as ações, como algum componente pedindo para alterar algum dado da store, por exemplo.
Para todo dado contido na store, deve existir um reducer próprio daquele dado.
Tecnicamente, reducer é uma função JavaScript que recebe o estado anterior, ou um estado definido com padrão no seu parâmetro, e uma action e, dependendo do type dessa action pode gerar um novo estado, o que implica que nem sempre teremos evolução do estado.
Então, dentro dos reducers, temos as actions.
Todo reducer ouve todas as actions disparadas pela aplicação e para alterar qualquer informação do estado, precisamos utilizar os reducers.
Anatomia de um reducer
const initialState = {...}
function exemploReducer1(state = initialState, action) {
switch(action.type) {
case ‘TYPE_1’ :
return { ...state, data: action.payload.data };
default:
return state;
}
}
Actions
São fontes de informações que são enviadas da aplicação para o store pelos reducers. São disparadas (dispatch) pelos actions creators (funções puras responsáveis por criarem as actions). Ainda vamos falar mais sobre os actions creators.
Tecnicamente, uma action é um objeto que possui, obrigatoriamente, um atributo nomeado type que indica que ação é. Pode ter dados associados ou não, mas geralmente possuem. Esses dados são reunidos em único atributo chamado de payload.
Como sugerido acima, um payload é um conjunto de dados, mas também pode ser, por exemplo, uma chamada para back-end.
Actions não realiza nenhuma alteração em nosso estado global. Lembre-se, são apenas objetos.
Anatomia da Action
{
type: “TIPO_DO_EVENTO”,
payload: {
// dados associados a essa action
}
}
Action Creator
Actions creators são funções puras responsáveis por criarem as actions.
function func1(params) {
// lógica
return {
type: “TIPO_EVENTO”,
payload: {
// dados associados a essa action
}
}
}
Estado (estado compartilhado)
Basicamente, é um objeto JavaScript com uma estrutura chave/valor.
{
atributo1: [ {...}, {...}, … ],
atributo2: {...}
}
Lembrando que o estado é gerado a partir de uma função.
Conexão dos componentes ao Redux
Para ter acesso à evolução de estados da store e disparar eventos para evoluí-la, é preciso se conectar/inscrever-se ao Redux. E como fazemos isso?
São basicamente dois passos:
1º passo: as importações.
import { bindActionCreators } from ‘redux’
import { connect } from ‘react-redux’
// e se você tiver um arquivos de actions creators, importe também.
Agora seja um componente baseado em classe ou em função, no final do arquivo deve existir algo mais ou menos assim:
2º passo: conexão.
const mapDispatchToProps = (dispatch) => bindActionCreators({...}, dispatch );
export default connect(null, mapDispatchToProps)( //nome do componente );
De boa até aqui? Vamos continuar…
Depois que conhecemos um pouco da teoria, vamos partir para a prática de um projeto muito simples, englobando sua criação, a instalação das dependências necessárias e utilização.
Criando um projeto usando o Redux
Para criar um projeto, precisamos do create-react-app instalado globalmente. Para que isso aconteça, rode o comando abaixo, caso você não o tenha.
npm i -g create-react-app
Agora, crie uma pasta qualquer, abra o terminal/cmd e o rode o comando abaixo escolhendo o nome do projeto de exemplo.
npx create-react-app [nome-do-projeto]
Instalação das dependências
Para utilizar o redux no seu projeto, precisamos instalá-lo. Podemos fazer utilizando o gerenciadores de pacote npm ou yarn.
NPM
npm install --save redux react-redux
Yarn
yarn add redux react-redux
Nesse sentido, a dependência “extra” é para fazer a conexão do React com o Redux.
Começando a utilização (configuração)
Crie uma pasta chamada storeConfig dentro de src do seu projeto. Dentro da pasta, crie um arquivo chamado store.js. O código escrito nele pode ser:
import { createStore, combineReducers } from ‘redux’
const reducers = combineReducers({
prop1: function(state, action) {
return {
exemplo: “Deu certo!’
}
},
prop2: function(state, action) {
return {
exemplo: “De novo, deu certo!”
}
})
function store() {
return createStore(reducers)
}
export default store
A função combine Reducers, como o próprio nome diz, combina todos os reducers da aplicação para criar a store. Para o nosso exemplo, temos dois reducers, mas é comum esse número ser muito maior em um projeto React.
Logo depois, abaixo, estamos encapsulando a criação da store pela função createStore (do Redux) dentro da função store e exportando-a.
Agora precisamos fazer a integração do React com o Redux.
No arquivo index.js da sua aplicação, as importações podem ser mais ou menos como abaixo:
import { Provider } from ‘react-redux’
import storeConfig from ‘./storeConfig/store’
const store = storeConfig()
Nesse arquivo, teremos algo assim:
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById(‘app’)
);
Agora ficará assim:
ReactDOM.render(
<Provider store={store}>
<React.StrictMode>
<App />
</React.StrictMode>
</Provider>,
document.getElementById(‘app’)
);
Pronto! Já temos a integração do React com Redux na sua aplicação. Agora, o que está faltando?
Como fazer o bind dos componentes com o estado da sua aplicação
Para isso, precisamos de um componente interessado nos dados da store. Dentro da pasta src do seu projeto, crie uma pasta chamada componentes. Feito isso, crie um arquivo exemploComponente.jsx dentro dessa pasta. Pode ser o nome que você quiser, e também poderá fazer algo realmente interessante para você.
Coloque o código abaixo no arquivo jsx criado:
import React, { Fragment } from ‘react’
import { connect } from ‘react-redux’
function exemplo(props) {
return (
<Fragment>
<div> props.prop1.exemplo</div>
<div> props.prop2.exemplo</div>
</Fragment>
)
}
function mapStateToProps(state) {
return {
prop1: state.prop1,
prop2.state.prop2
}
}
export default connect(mapStateToProps)(exemplo)
Assim, utilizamos o connect (do react-redux) para devolver o componente conectado com o estado global da aplicação. Ele é responsável por conectar o nosso componente ao estado global da aplicação.
A função mapStateToProps mapeia o estado para as propriedades do componente.
Prontinho! Veja o que já temos:
- Projeto criado.
- Dependências instaladas.
- Store criada.
- Componente conectado.
E já que estamos aqui, por que não alguns cursos gratuitos para você se aprofundar? Segue a lista:
- Redux Tutorial by Dan Abramov on
- Tutorial de React grátis – React, Redux e integração de APIs
- Getting Started with Redux
No YouTube existem vários que tratam do tema também.
Conclusão
A utilização do Redux torna o gerenciamento de estado da sua aplicação simples e escalável, tornando-a fácil de manter, uma vez que o acoplamento entre os componentes diminui drasticamente, ganhando, desse modo, em aspectos como produtividade.
O Redux se tornou uma solução quase que indispensável nas aplicações React, simplesmente por resolver algo complexo com tanta elegância.
Uma observação: ainda assim não são todas as aplicações React que necessitam do Redux. Depende mesmo do grau de comunicação entre os componentes da sua aplicação.
Por outro lado, existe uma necessidade de análise para saber quais são os estados que realmente devem estar no Store.
Só mais uma coisinha… existe algo relacionado ao Redux que é muito comum. São os middlewares. Não é do escopo deste artigo falar sobre eles, mas fica a ciência sobre sua existência.
Espero que tenham gostado do conteúdo, lembrem-se de acessar o projeto no link acima e até a próxima!
Bons estudos! 😊