Introdução ao Redux (usando apenas Javascript)

Lucas Ferreira
Jaguaribe Tech
Published in
9 min readFeb 17, 2018

Update 2020: Criei minha própria plataforma e agora meus posts a partir da agora vão estar hospedados em https://www.lucasfrosty.me/blog, entra lá e dá uma conferida ;)

E ai galerinha, tudo firmeza? Ainda na tentativa de cumprir minha promessa de voltar a escrever mais artigos, dessa vez vou falar de uma lib bem bacana que é o Redux. E para isso utilizarei apenas o bom e velho Javascript.

Pois é, meus queridos. Devido ao fato do Redux ser uma lib que tem uma ligação muito forte com o React, é muito comum ver tutoriais e artigos na Internet ensinando sobre o Redux já utilizando diretamente com React. Porém é importante salientar que você não depende do React para utilizá-lo, você pode utilizar o view framework da sua preferência, ou até, como será o nosso caso aqui, sem utilizar framework algum. Eu preferi essa abordagem pois eu posso focar mais diretamente no Redux e deixar a parte da conectividade com o React para, quem sabe, um próximo artigo (2k18 goals).

Ah, e como eu sou um cara super criativo, vou fazer algo inédito na televisão brasileira e montar um To-do list.

Bom, dada essa breve explicação sobre o artigo, vamos ao que interessa. Sigam-me os bons!

O que é Redux?

Logozinha top do Redux

Redux é uma Biblioteca Open-Source criada por Dan Abramov e Andrew Clark, sua principal função é gerenciar o estado de uma aplicação. Redux foi inspirada na arquitetura Flux e trazendo também alguns princípios arquiteturais da linguagem Elm.

Bom, pra entender como ele funciona, precisamos entender alguns conceitos (usarei os termos em inglês, pois é como você deve aprender mesmo):

(1) State

State são dados que são responsáveis por mostrar como a nossa aplicação estará em um determinado momento. No caso do Redux esses dados estarão alocados em apenas um grande Objeto (ou Array) chamado store (eu particularmente chamo state de store e vice-versa). A idéia é que esse state tenha um valor inicial (quando a aplicação é carregada) e conforme o usuário for interagindo com a aplicação, esse state irá se alterando e, consequentemente, a UI também será alterada.

(2) Store

Como dito acima, é simplesmente um objeto (ou array) que guardará o nosso state. Importante salientar que a store é imutável, ou seja, sempre que temos uma alteração nela (seja mudar, acrescentar ou remover um valor/variável), ao invés de alterá-lo, criamos um novo store com essas novas informações.

(3) View

É a nossa UI que irá variar, conforme falado acima, de acordo com o state da aplicação.

(4) Actions

São as informações que serão passadas para store, a Action nada mais é que um objeto que contém o type, e as vezes, um payload (valor). Sua execução acontece através do comando store.dispatch(), que será responsável por dispachar essa ação para o Reducer. No exemplo explicarei um pouco melhor seu funcionamento.

(5) Reducer

É a função responsável por receber a action, e baseado no seu type, fazer as alterações necessárias no state e aplicá-las na store (sempre de forma imutável, ou seja, criando uma nova store).

Bom, aposto que por enquanto você tá sem entender nada, não é mesmo? Mas relaxa, vamos pra prática e (talvez) as coisas fiquem mais claras pra você.

Exemplo: To-do list

Bom, o código completo (incluindo o HTML e o CSS) está disponível no Codepen abaixo ou, para ver em mais detalhes, clicando aqui.

Irei daqui em diante explorar o código em “blocos” e ir explicando o que cada um deles fazem (usando a mesma ordem de conceitos mostrados lá em cima).

Criação da store

Primeiramente, no HTML eu importei o script do Redux dentro do projeto. Como estou utilizando o Codepen, optei por fazer a importação através de uma tag script. Mas o que eu fiz aqui seria a mesma coisa que fazer algo como npm install redux em um projeto normal usando npm.

Esse script me deu acesso a uma váriavel dentro do meu arquivo Javascript chamada Redux.

Para criar o store é muito simples, basta utilizar a função Redux.createStore() e passando o Reducer como parâmetro (calmaê que eu vou falar do Reducer jajá).

Enviando uma Action

Explicando o que tá acontecendo:

Primeiramente, estou adicionando um event listener de submit no formulário (que é aquele input de adicionar um TODO).

Dentro do callback desse event listener eu estou pegando o valor do input, verificando se foi digitado alguma coisa nele, e caso sim eu…

Chamo a função store.dispatch(), que é responsável por dispachar uma Action para o Reducer, seu parâmetro é um objeto contendo as informações que essa Action terá. Conforme eu disse lá em cima, toda ação tem um type, que nada mais é do que um identificador que será usado pelo Reducer para que ele saiba o que fazer com esse dado; e o payload, que são os dados que serão acrescentados na store.

Percebam que nesse caso minha action ficou assim:

{
type: ADD_TODO, // variável criada na linha 1
payload: {
value, // value: value (onde value é o valor do input)
id: _.uniqueId(), // um método do lodash p/ criar um ID único
completed: false, // explicitando que eu não completei aquela tarefa ainda.
}
}

Resumindo: o que eu estou fazendo é adicionar um TODO com o value do input, um ID único e passando também a informação de que eu ainda não fiz aquela tarefa.

Por fim, zero o valor do input após enviar o TODO para o store.

Tratando a Action dentro do Reducer

Conforme eu disse lá em cima, toda Action é dispachada para o Reducer, que agora tem a responsabilidade de tratar essa Action e fazer as mudanças necessárias.

Um Reducer nada mais é do que uma função que recebe como parâmetros o state atual e a Action dispachada pelo store.dispatch(). Então toda vez que um um store.dispatch() for executado, o Reducer entrará em ação.

No nosso exemplo, o state nada mais é do que um Array de TODOS, onde as informações do TODO é aquele objeto com value, id e completed que eu dispachei como payload lá em cima.

Então percebam que o que o Reducer faz é, primeiramente filtrar, através de um switch-case (pode ser com if também, vai de cada um) qual o tipo daquela Action, pois cada Action irá fazer coisas diferentes com o nosso state (por exemplo, uma Action do tipo ADD_TODO irá adicionar um TODO ao nosso Array, enquanto que a do tipo REMOVE_TODO vai remover um TODO do array).

Lembram que lá em cima eu dispachei uma action com o type: ADD_TODO, certo? Então… o nosso Reducer irá verificar qual type foi declarado, e então entrará no case ADD_TODO, que irá executar o código da imagem acima. E, bom, o que esse código faz, nada mais é do que, criar um novo state pegando o state antigo, e acrescentando a ele um novo TODO com as informações contidas no payload. Porém, é importante salientar que ele faz isso de forma imutável.

Mas como funciona essa Imutabilidade?

Infelizmente eu não irei abordar imutabilidade a fundo nesse artigo pois ele já está muito extenso, eu pretendo futuramente criar um artigo sobre isso, mas até lá fiquem com esse artigo que explica bem como funciona imutabilidade no Javascript e esse link explicando os benefícios da imutabilidade no Redux.

E, por fim, a Subscription

A subscription nada mais é do que, uma (ou mais de 1) função que será executada toda vez que uma Action for disparada. No nosso caso, a função que será executada é a de render:

Primeiramente eu estou logando o valor atual do state (vocês podem ver isso no gif mais abaixo) através do comando store.getState().

Após isso o que eu irei fazer é, injetar na View, mais especificamente dentro da div com id todos-container (que foi criada no HTML) uma outra div para cada TODO contido no state. Percebam também que eu estou usando os valores desse TODO (id, completed e value) para, dinâmicamente, criar o seu conteúdo.

store.getState()

Valores do store.getState()

Resumão

  1. A aplicação foi carregada com o state inicial de um Array vazio (pois nenhum TODO ainda foi colocado).
  2. Quando eu submeto um novo TODO ao TODO-list eu dispacho uma nova Action do tipo ADD_TODO para o Reducer com as informações contidas no payload.
  3. Após essa ação ser disparada, o Reducer irá fazer o tratamento dessas informações e decidir o que fazer com elas baseado na action.type (nesse caso action.type === ADD_TODO). E tudo isso de maneira imutável.
  4. Após o Reducer fazer seu trabalho, a função render() será executada, pois definimos isso através do store.subscription(render).
  5. A função render() irá popular a View dinânicamente com os dados contido na store.
  6. O clico se repete e se aplica as outras Actions também (TOGGLE_TODO e REMOVE_TODO).

Bom, acho que o exemplo termina por aqui. Não chegarei a falar sobre o funcionamento do TOGGLE_TODO e REMOVE_TODO, pois, novamente o artigo ficaria enorme. Fica como lição de casa pra vocês (quem conseguir entender as 3 Actions já pode pedir música no Fantástico).

Usabilidade

O Redux é mais usados para quem precisa de um fluxo de dados mais controlado e centralizado em um único objeto (ou Array), e isso cai como uma luva pra quem utiliza frameworks como React e Angular, onde o fluxo de dados pode se tornar um pouco caótico. Porém, nesse artigo eu fiz algo diferente e trouxe uma utilização com apenas Javascript, pois minha proposta era fazer com que você pudesse entender o funcionamento da biblioteca em sí e posteriormente buscasse entender como ela se conecta com outros frameworks. Se você pretende utilizá-lo com React, recomendo ler esse artigo do Dan Abramov (criador do Redux) sobre quando é o cenário correto para utilizá-lo, pois, como vocês puderam ver, fazer o setup dessa ferramenta dentro de um projeto é um pouco complicado e, muitas vezes, não vale a pena.

Links úteis

E fim!

Bom galera, acho que é isso. Tentei trazer uma abordagem diferente sobre o funcionamento do Redux. Se as coisas ainda não estão muito claras pra você, tudo bem, é normal; Redux é um conteúdo extremamente complicado e que requer muita prática pra pegar seu funcionamento (falo por experiência própria, demorei umas 2 semanas praticando forte pra poder entender uma vez por todas como todo esse fluxo maluco funciona).

Fique a vontade também para me seguir aqui no Medium e no Github:

Vejo vocês no próximo artigo, falows!

--

--