Redux · Uma Introdução

Publicados: 2022-03-10
Resumo rápido ↬ Redux é uma das bibliotecas mais populares no desenvolvimento front-end atualmente. No entanto, muitas pessoas estão confusas sobre o que é e quais são seus benefícios. Como afirma a documentação, o Redux é um contêiner de estado previsível para aplicativos JavaScript . Para reformular isso, é uma arquitetura de fluxo de dados de aplicativo, em vez de uma biblioteca tradicional ou uma estrutura como Underscore.js e AngularJS.

Redux é uma das bibliotecas mais populares no desenvolvimento front-end atualmente. No entanto, muitas pessoas estão confusas sobre o que é e quais são seus benefícios.

Como a documentação afirma, o Redux é um contêiner de estado previsível para aplicativos JavaScript. Para reformular isso, é uma arquitetura de fluxo de dados de aplicativo, em vez de uma biblioteca tradicional ou uma estrutura como Underscore.js e AngularJS.

Leitura adicional no SmashingMag

  • Por que você deve considerar o React Native para seu aplicativo móvel
  • Automação de teste para aplicativos, jogos e a Web para dispositivos móveis
  • Renderização do lado do servidor com React, Node e Express
  • Observações sobre acessibilidade renderizada pelo cliente

Redux foi criado por Dan Abramov por volta de junho de 2015. Foi inspirado no Flux do Facebook e na linguagem de programação funcional Elm. O Redux se popularizou muito rapidamente devido à sua simplicidade , tamanho pequeno (apenas 2 KB) e ótima documentação. Se você quiser aprender como o Redux funciona internamente e mergulhar fundo na biblioteca, considere conferir o curso gratuito de Dan.

Mais depois do salto! Continue lendo abaixo ↓

O Redux é usado principalmente para gerenciamento de estado do aplicativo. Para resumir, o Redux mantém o estado de uma aplicação inteira em uma única árvore de estado imutável (objeto), que não pode ser alterada diretamente. Quando algo muda, um novo objeto é criado (usando ações e redutores). Veremos os conceitos principais em detalhes abaixo.

Como é diferente do MVC e do Flux?

Para dar alguma perspectiva, vamos pegar o padrão clássico model-view-controller (MVC), já que a maioria dos desenvolvedores está familiarizada com ele. Na arquitetura MVC, há uma separação clara entre dados (modelo), apresentação (view) e lógica (controlador). Há um problema com isso, especialmente em aplicativos de grande escala: o fluxo de dados é bidirecional. Isso significa que uma alteração (uma entrada do usuário ou resposta da API) pode afetar o estado de um aplicativo em muitos lugares no código — por exemplo, vinculação de dados bidirecional. Isso pode ser difícil de manter e depurar.

O Flux é muito semelhante ao Redux. A principal diferença é que o Flux possui várias lojas que alteram o estado do aplicativo e transmite essas alterações como eventos. Os componentes podem assinar esses eventos para sincronizar com o estado atual. O Redux não possui um dispatcher , que no Flux é usado para transmitir cargas úteis para retornos de chamada registrados. Outra diferença no Flux é que muitas variedades estão disponíveis, e isso cria alguma confusão e inconsistência.

Benefícios do Redux

Você pode estar se perguntando: “Por que eu precisaria usar o Redux?” Ótima pergunta. Existem alguns benefícios de usar o Redux em seu próximo aplicativo:

  • Previsibilidade do resultado
    Há sempre uma fonte de verdade, a loja, sem confusão sobre como sincronizar o estado atual com ações e outras partes do aplicativo.
  • Manutenibilidade
    Ter um resultado previsível e uma estrutura rígida facilita a manutenção do código.
  • Organização
    O Redux é mais rigoroso sobre como o código deve ser organizado, o que torna o código mais consistente e fácil para uma equipe trabalhar.
  • Renderização do servidor
    Isso é muito útil, especialmente para a renderização inicial, melhorando a experiência do usuário ou a otimização do mecanismo de pesquisa. Basta passar a loja criada no servidor para o lado do cliente.
  • Ferramentas de desenvolvimento
    Os desenvolvedores podem acompanhar tudo o que está acontecendo no aplicativo em tempo real, desde ações até alterações de estado.
  • Comunidade e ecossistema
    Esta é uma grande vantagem sempre que você estiver aprendendo ou usando qualquer biblioteca ou estrutura. Ter uma comunidade por trás do Redux torna o uso ainda mais atraente.
  • Facilidade de teste
    A primeira regra para escrever código testável é escrever pequenas funções que fazem apenas uma coisa e que são independentes. O código do Redux é principalmente funções que são apenas isso: pequenas, puras e isoladas.

Programação Funcional

Como mencionado, o Redux foi construído sobre conceitos de programação funcional. Compreender esses conceitos é muito importante para entender como e por que o Redux funciona da maneira que funciona. Vamos rever os conceitos fundamentais da programação funcional:

  • É capaz de tratar funções como objetos de primeira classe.
  • É capaz de passar funções como argumentos.
  • É capaz de controlar o fluxo usando funções, recursões e arrays.
  • É capaz de usar funções puras, recursivas, de ordem superior, de fechamento e anônimas.
  • É capaz de usar funções auxiliares, como mapear, filtrar e reduzir.
  • É capaz de encadear funções em conjunto.
  • O estado não muda (ou seja, é imutável).
  • A ordem de execução do código não é importante.

A programação funcional nos permite escrever um código mais limpo e modular. Ao escrever funções menores e mais simples que são isoladas em escopo e lógica, podemos tornar o código muito mais fácil de testar, manter e depurar. Agora, essas funções menores se tornam código reutilizável , e isso permite que você escreva menos código, e menos código é uma coisa boa. As funções podem ser copiadas e coladas em qualquer lugar sem qualquer modificação. Funções que são isoladas no escopo e que executam apenas uma tarefa dependerão menos de outros módulos em um aplicativo, e esse acoplamento reduzido é outro benefício da programação funcional.

01-functional-programming-opt-preview
Exemplo de programação funcional (Imagem: Tanya Bachuk) (Ver versão ampliada)

Você verá funções puras, funções anônimas, encerramentos, funções de ordem superior e cadeias de métodos, entre outras coisas, com muita frequência ao trabalhar com JavaScript funcional. O Redux usa muito funções puras, então é importante entender o que elas são.

Funções puras retornam um novo valor com base nos argumentos passados ​​a elas. Eles não modificam objetos existentes; em vez disso, eles retornam um novo. Essas funções não dependem do estado de onde são chamadas e retornam apenas um e o mesmo resultado para qualquer argumento fornecido. Por esta razão, eles são muito previsíveis.

Como as funções puras não modificam nenhum valor, elas não têm nenhum impacto no escopo ou efeitos colaterais observáveis, e isso significa que um desenvolvedor pode se concentrar apenas nos valores que a função pura retorna.

Onde o Redux pode ser usado?

A maioria dos desenvolvedores associa o Redux ao React, mas ele pode ser usado com qualquer outra biblioteca de visualização. Por exemplo, você pode usar Redux com AngularJS, Vue.js, Polymer, Ember, Backbone.js e Meteor. Redux mais React, no entanto, ainda é a combinação mais comum. Certifique-se de aprender React na ordem correta: O melhor guia é o de Pete Hunt, que é muito útil para desenvolvedores que estão começando com o React e estão sobrecarregados com tudo o que está acontecendo no ecossistema. A fadiga do JavaScript é uma preocupação legítima entre os desenvolvedores front-end, novos ou experientes, então reserve um tempo para aprender React ou Redux da maneira certa na ordem certa.

Uma das razões pelas quais o Redux é incrível é o seu ecossistema. Muitos artigos, tutoriais, middleware, ferramentas e clichês estão disponíveis. Pessoalmente, eu uso o clichê de David Zukowski porque ele tem tudo o que se precisa para construir uma aplicação JavaScript, com React, Redux e React Router. Uma palavra de cautela: tente não usar clichês e kits iniciais ao aprender novos frameworks, como React e Redux. Isso tornará ainda mais confuso, porque você não entenderá como tudo funciona em conjunto. Aprenda primeiro e construa um aplicativo muito simples, idealmente como um projeto paralelo, e depois use clichês para aplicativos de produção para economizar tempo.

Construindo Partes do Redux

Os conceitos do Redux podem parecer complicados ou extravagantes, mas são simples. Lembre-se que a biblioteca tem apenas 2 KB. Redux tem três partes de construção: ações, armazenamento e redutores.

02-redux-data-flow-opt-preview
Fluxo de dados do Redux (Imagem: Tanya Bachuk) (Ver versão ampliada)

Vamos discutir o que cada um faz.

Ações

Em poucas palavras, ações são eventos. As ações enviam dados do aplicativo (interações do usuário, eventos internos, como chamadas de API e envios de formulários) para a loja. A loja obtém informações apenas de ações. Ações internas são objetos JavaScript simples que possuem uma propriedade de type (geralmente constante), descrevendo o tipo de ação e a carga útil das informações que estão sendo enviadas para a loja.

 { type: LOGIN_FORM_SUBMIT, payload: {username: 'alex', password: '123456'} }

As ações são criadas com criadores de ações. Isso parece óbvio, eu sei. São apenas funções que retornam ações.

 function authUser(form) { return { type: LOGIN_FORM_SUBMIT, payload: form } }

Chamar ações em qualquer lugar do aplicativo é muito fácil. Use o método dispatch , assim:

 dispatch(authUser(form));

Redutores

Já discutimos o que é um redutor em JavaScript funcional. Ele é baseado no método de redução de matriz, onde ele aceita um retorno de chamada (redutor) e permite obter um único valor de vários valores, somas de números inteiros ou um acúmulo de fluxos de valores. No Redux, os redutores são funções (puras) que pegam o estado atual da aplicação e uma ação e depois retornam um novo estado. Entender como os redutores funcionam é importante porque eles realizam a maior parte do trabalho. Aqui está um redutor muito simples que recebe o estado atual e uma ação como argumentos e retorna o próximo estado:

 function handleAuth(state, action) { return _.assign({}, state, { auth: action.payload }); }

Para aplicativos mais complexos, é possível usar o utilitário combineReducers() fornecido pelo Redux (na verdade, recomendado). Ele combina todos os redutores do aplicativo em um único redutor de índice. Cada redutor é responsável por sua própria parte do estado do aplicativo e o parâmetro de estado é diferente para cada redutor. O utilitário combineReducers() torna a estrutura do arquivo muito mais fácil de manter.

Se um objeto (estado) altera apenas alguns valores, o Redux cria um novo objeto, os valores que não foram alterados irão se referir ao objeto antigo e somente novos valores serão criados. Isso é ótimo para o desempenho. Para torná-lo ainda mais eficiente, você pode adicionar Immutable.js.

 const rootReducer = combineReducers({ handleAuth: handleAuth, editProfile: editProfile, changePassword: changePassword });

Armazenar

Store é o objeto que mantém o estado do aplicativo e fornece alguns métodos auxiliares para acessar o estado, despachar ações e registrar ouvintes. Todo o estado é representado por uma única loja. Qualquer ação retorna um novo estado por meio de redutores. Isso torna o Redux muito simples e previsível.

 import { createStore } from 'redux'; let store = createStore(rootReducer); let authInfo = {username: 'alex', password: '123456'}; store.dispatch(authUser(authInfo));

Ferramentas do desenvolvedor, viagem no tempo e recarga a quente

Para tornar o Redux mais fácil de trabalhar, especialmente ao trabalhar com um aplicativo de grande escala, recomendo usar o Redux DevTools. É incrivelmente útil, mostrando as mudanças do estado ao longo do tempo, mudanças em tempo real, ações e o estado atual. Isso economiza tempo e esforço evitando o estado atual e as ações do console.log

03-redux-dev-tools-opt-preview
Redux DevTools (Ver versão grande)

Redux tem uma implementação de viagem no tempo ligeiramente diferente do Flux. No Redux, você pode voltar a um estado anterior e até mesmo levar seu estado em uma direção diferente a partir desse ponto. O Redux DevTools suporta os seguintes recursos de “viagem no tempo” no fluxo de trabalho do Redux (pense neles como comandos Git para seu estado):

  • Redefinir : redefine para o estado com o qual sua loja foi criada
  • Revert : volta para o último estado confirmado
  • Sweep : remove todas as ações desabilitadas que você pode ter disparado por engano
  • Commit : torna o estado atual o estado inicial

O recurso de viagem no tempo não é eficiente na produção e destina-se apenas ao desenvolvimento e depuração. O mesmo vale para DevTools.

Redux torna o teste muito mais fácil porque usa JavaScript funcional como base, e pequenas funções independentes são fáceis de testar. Portanto, se você precisar alterar algo em sua árvore de estados, importe apenas um redutor que seja responsável por esse estado e teste-o isoladamente.

Crie um aplicativo

Para concluir este guia introdutório, vamos construir uma aplicação muito simples usando Redux e React. Para facilitar o acompanhamento de todos, vou me ater ao JavaScript simples e antigo, usando o ECMAScript 2015 e 2016 o mínimo possível. Continuaremos a lógica de login iniciada anteriormente neste post. Este exemplo não usa dados ao vivo, pois o objetivo deste aplicativo é mostrar como o Redux gerencia o estado de um aplicativo muito simples. Usaremos CodePen.

1. Reagir Componente

Precisamos de alguns componentes e dados do React. Vamos fazer um componente simples e renderizá-lo na página. O componente terá um campo de entrada e um botão (é um formulário de login muito simples). Abaixo, adicionaremos o texto que representa nosso estado:

Veja a introdução da caneta ao Redux por Alex Bachuk (@abachuk) no CodePen.

Veja a introdução da caneta ao Redux por Alex Bachuk (@abachuk) no CodePen.

2. Eventos e Ações

Vamos adicionar Redux ao projeto e manipular o evento onClick para o botão. Assim que o usuário logar, enviaremos a ação com o tipo LOGIN e o valor do usuário atual. Antes de podermos fazer isso, temos que criar uma loja e passar uma função redutora para ela como um argumento. Por enquanto, o redutor será apenas uma função vazia:

Veja a Introdução da caneta ao Redux - Etapa 2. Eventos e ações por Alex Bachuk (@abachuk) no CodePen.

Veja a Introdução da caneta ao Redux - Etapa 2. Eventos e ações por Alex Bachuk (@abachuk) no CodePen.

3. Redutores

Agora que temos a ação disparada, o redutor executará essa ação e retornará um novo estado. Vamos tratar da ação LOGIN retornando um status de logado e também adicionar uma ação LOGOUT , para que possamos usá-la posteriormente. O redutor auth aceita dois parâmetros:

  1. o estado atual (que tem o valor padrão),
  2. a acção.

Veja o Pen Intro to Redux - Step 3. Reducers por Alex Bachuk (@abachuk) no CodePen.

Veja o Pen Intro to Redux - Step 3. Reducers por Alex Bachuk (@abachuk) no CodePen.

4. Exibindo o estado atual

Agora que temos o estado inicial (o valor padrão no redutor) e o componente React prontos, vamos ver como fica o estado. Uma prática recomendada é empurrar o estado para componentes filhos. Como temos apenas um componente, vamos passar o estado do aplicativo como uma propriedade para componentes de auth . Para fazer tudo funcionar em conjunto, temos que registrar o ouvinte da loja com um método auxiliar de subscribe , envolvendo ReactDOM.render em uma função e passando para store.subscribe() :

Veja Pen Intro to Redux - Step 4. Exibindo o estado atual por Alex Bachuk (@abachuk) no CodePen.

Veja Pen Intro to Redux - Step 4. Exibindo o estado atual por Alex Bachuk (@abachuk) no CodePen.

5. Entrar e sair

Agora que temos manipuladores de ação de login e logout, vamos adicionar um botão de logout e despachar a ação LOGOUT . A última etapa é gerenciar qual botão exibir o login ou logout movendo este login para fora do método de renderização e renderizando a variável abaixo:

Veja a Introdução da caneta ao Redux - Etapa 5. Login/Logout por Alex Bachuk (@abachuk) no CodePen.

Veja a Introdução da caneta ao Redux - Etapa 5. Login/Logout por Alex Bachuk (@abachuk) no CodePen.

Conclusão

Redux está ganhando força a cada dia. Tem sido usado por muitas empresas (Uber, Khan Academy, Twitter) e em muitos projetos (Apollo, WordPress' Calypso), com sucesso em produção. Alguns desenvolvedores podem reclamar que há muita sobrecarga. Na maioria dos casos, é necessário mais código para executar ações simples, como cliques em botões ou alterações simples na interface do usuário. Redux não é um ajuste perfeito para tudo. Tem que haver um equilíbrio. Talvez ações simples e mudanças na interface do usuário não precisem fazer parte da loja Redux e possam ser mantidas no nível do componente.

Mesmo que o Redux possa não ser a solução ideal para o seu aplicativo ou framework, recomendo fortemente que o verifique, especialmente para aplicativos React.

Créditos da imagem da primeira página: Lynn Fisher, @lynnandtonic