Um guia para principiantes do Redux

Safeer Hayat 27 dez Logotipo oficial do Redux

Compreender o Redux como um iniciante pode ser bastante confuso. O Redux tem uma abundância de novos termos e conceitos que muitas vezes são pouco intuitivos. Este guia apresenta um exemplo muito simplificado de uma implementação do Redux. Vou definir cada um dos passos e termos de uma maneira que faça sentido para um iniciante completo.

Este destina-se a ser um guia para desmistificar os elementos do Redux. Não contém as definições tecnicamente mais precisas. Não tem as melhores práticas de sempre. Ele possui definições que ajudarão a desenvolver uma compreensão para alguém sem conhecimento prévio desses conceitos. Existe uma implementação simples para não confundir com detalhes desnecessários.

O exemplo que percorreremos neste guia será um aplicativo de tarefas simples. O aplicativo permite que um usuário adicione ou remova itens de tarefas e os veja exibidos na página.

Eu vou percorrer passo a passo cada elemento do Redux, explicando o que é esse elemento e como implementá-lo com exemplos de código. Role até o final para ver o exemplo de código completo que mostrará como tudo se encaixa como um aplicativo React completo.

Resumo das etapas

  1. Escreva a função de redutor
  2. Instanciar o armazenamento no componente raiz
  3. Enrole os componentes com o componente <Provider>, passando a loja como um suporte
  4. Escreva o componente
  5. Definir as ações
  6. Defina o despacho, anexe-os ao local onde os despachos serão acionados (ou seja, ouvintes de eventos, etc.)
  7. Definir a função mapStateToProps
  8. Exportar a função de conexão, passando em mapStateToProps e null como os 2 argumentos e passando o nome do componente no segundo par de colchetes

Passos

1. Escreva a função de redutor

A função de redutor é uma função que diz à loja como responder a ações. A função retorna o estado novo e atualizado sempre que uma ação é despachada. O estado é imutável (não pode ser alterado), portanto, o redutor sempre retorna um novo estado. O redutor geralmente usa o operador spread para inserir o estado atual em um novo objeto / array e anexá-lo a ele. A prática comum é usar uma instrução switch / case e verificar a propriedade type da ação passada. Em seguida, escreva o código que atualiza o estado para cada caso.

Escrevemos nossa função de redutor primeiro, porque precisaremos passar isso quando instanciamos nossa loja. Para entender o que está acontecendo, é necessário algum conhecimento de ações e envio. Vamos abordar isso mais adiante neste guia.

Por agora, saiba que nosso aplicativo todo precisará interagir com a loja de duas maneiras: para adicionar um novo item de tarefa ao estado e para remover um item de tarefa do estado. Portanto, escrevemos nossa função para que ela responda a dois casos do tipo de ação. Ele usa o valor de ação para adicionar ou remover um item todo do estado.

O redutor é passado 2 parâmetros: estado (este é o estado inteiro atualmente na loja, e damos a ele um valor padrão se o estado ainda não existir) e a ação. Nós retornamos o estado no caso padrão.

Função de redutor com 2 casos

2. Instancie a loja no componente raiz

A loja é a coisa que realmente contém o estado nela. É um pouco mágico e você realmente não precisa saber os detalhes dele. Tudo o que você precisa saber é que não o acessa diretamente como faria em um estado normal de Reação. Você acessa e faz alterações usando redutores, ações e despachos.

A outra coisa importante a saber sobre a loja é que ela contém alguns métodos úteis e importantes. O principal método é a função de despacho. Ele também contém um método getState (para visualizar o estado) e um método de assinatura (executa um retorno toda vez que uma ação é despachada).

A loja é normalmente instanciada na raiz do seu aplicativo (por exemplo, App.js). Ele é armazenado como uma variável e tem o redutor passado como um parâmetro. A loja é então passada como um prop para o componente Provider.

Instanciamos nosso objeto de loja passando no redutor que acabamos de criar.

Armazenar instanciado com o redutor que criamos na etapa anterior

3. Envolva os componentes com o componente <Provider>, passando a loja como um suporte

O Provedor é um componente criado para facilitar a passagem da loja para todos os seus componentes. O componente Provider envolve todos os seus componentes (por exemplo, renderize seus componentes como filhos do Provider). Você passa a loja como um suporte apenas para o Provedor. Isso significa que você não precisa passar na loja como um acessório para cada componente, pois cada componente o obtém do Provedor. No entanto, isso não significa que os componentes tenham acesso ao estado ainda. Você ainda precisa usar o mapStateToProps (nós cobriremos isso mais tarde) para ter o estado acessível em seu componente.

Nós envolvemos o componente Todo que vamos fazer com o nosso componente Provider. Nós passamos na loja que criamos na etapa anterior.

Componentes são empacotados com o componente Provider com a loja passada em

4. Escreva o componente

Em seguida, começamos a escrever o componente Todo, que renderizará os itens de tarefas e interagirá com a loja Redux.

O componente é um componente com estado que contém um elemento de estado para acompanhar o que o usuário digitou na entrada. Nós temos uma função chamada handleChange. Esta função atualiza o estado toda vez que o usuário digita algo na entrada. Até agora isso é tudo que vamos escrever. Precisamos entender mais sobre o Redux antes de podermos escrever a lógica. A lógica adicionará novos itens ao estado e recuperará os atuais do estado para renderizar na página.

O início do componente Todo, que permite ao usuário inserir novos itens de tarefas

5. Defina as ações

Uma ação é um objeto simples que contém uma propriedade chamada 'tipo'. Este objeto é passado para a função de despacho. Ele é usado para informar à loja qual evento acabou de ocorrer (lendo a propriedade type). Também informa qual atualização deve ser feita ao estado em resposta (através da função redutor). A ação também pode conter outras propriedades para qualquer outro dado que você queira passar para o redutor. Os dados só podem ser passados por aqui para que os dados necessários precisem ser passados aqui.

Vamos usar criadores de ações para definir nossas ações. Criadores de ações são uma função que retorna o objeto de ação. Sua finalidade é tornar a ação mais portátil e testável. Isso não muda o comportamento de como tudo funciona. É outro método de escrever e passar a ação. Ele também permite que você passe parâmetros se quiser enviar dados com a ação que estaremos fazendo. Então, precisamos usar criadores de ação aqui.

Se você se lembra de nosso redutor respondeu a dois tipos de ação – "ADD_TODO" e "REMOVE_TODO". Vamos definir essas ações com nossos criadores de ação. Em nossa ação add_todo retornará “ADD_TODO” como o tipo e o item todo que queremos adicionar à loja como o valor (precisamos que a loja adicione esse item todo ao estado para que seja passada aqui). No remove_todo, retornamos “REMOVE_TODO” como o tipo e o índice do item todo na loja como o valor. Vamos precisar disso para removê-lo da lista de todos.

Nós definimos nossas duas ações aqui em criadores de ação. É o que nosso redutor lê quando é acionado para atualizar o estado.

Se você retornar à nossa função de redutor, esperamos que agora faça mais sentido. Ao ler o action.type, o redutor sabe se precisa adicionar um todo ao estado ou remover um dele. Tem o item todo passado no add_todo. Ele é anexado ao estado atual usando o operador spread. No remove_todo ele usa o operador spread para criar um novo array anexando o estado atual cortado duas vezes, uma vez com todos os elementos antes do que remover e segundo com todos os elementos após o que remover, criando assim nosso novo objeto de estado com o item todo removido.

A função de redutor que definimos anteriormente

No entanto, isso ainda não é uma imagem completa. Ainda não cobrimos como o redutor é chamado e passado na ação correta. Para isso, precisaremos seguir em frente para definir nossa função de despacho.

6. Defina o despacho, anexe-os ao local onde os despachos serão acionados (ou seja, ouvintes de eventos, etc.)

A função de despacho é um método da loja que é usado para acionar uma mudança no estado. Qualquer evento ou qualquer coisa que precise atualizar o estado deve chamar o método de dispatch para fazer isso. Esta é a única maneira de acionar uma alteração / atualização do estado. Dispatch é chamado e o objeto de ação é passado (ou o criador da ação, se isso foi usado). Uma vez que um despacho é acionado, o armazenamento chama a função de redutor e passa a ação que o despacho forneceu, atualizando o estado, como vimos anteriormente.

Abaixo, definimos a metade inferior do nosso método de renderização Componentes. Criamos nossos botões que conterão nossos manipuladores de eventos. Dentro deles, definiremos nossas funções de despacho.

O primeiro botão é um simples botão de adição. Este botão irá despachar a ação add_todo para a loja. Ele passará na entrada atual do usuário como o valor (este é o item todo que o redutor anexa ao novo estado). Note que chamamos dispatch como this.props.dispatch . É um pouco fora do escopo deste guia entender como e por que isso é passado como um acessório para o componente. Então, saiba que isso acontece e podemos chamá-lo assim.

O segundo manipulador de eventos é escrito como um onClick no nosso item todo processado. Clicando em qualquer item todo na página, ele aciona um manipulador de eventos. O manipulador de eventos pesquisa a lista de todos e localiza o índice desse todo na lista. Em seguida, despacha a ação remove_todo e passa no índice.

A metade inferior da nossa definição de componente, incluindo nossos manipuladores de eventos que chamam a função de despacho

O ciclo de como atualizar o estado na loja Redux está agora totalmente definido. Sabemos que sempre que quisermos alterar o estado, precisamos chamar o método de despacho, passar a ação apropriada e garantir que nosso redutor lide com essas ações e retorne o novo estado usando quaisquer valores que passamos por meio da ação.

A única peça de quebra-cabeça faltando agora é como obter o estado da loja Redux. Você provavelmente já percebeu que this.props.todos uma lista chamada this.props.todos no exemplo anterior. Você pode estar se perguntando de onde isso veio. Você também pode se lembrar que no início deste guia eu mencionei que a passagem da loja para o componente Provider não é suficiente para obter acesso ao estado na loja. Isso tudo é endereçado nas próximas 2 etapas, conforme definimos nossa função mapStateToProps e passamos isso para a função de conexão.

7. Defina a função mapStateToProps

Quando você quer que seu componente tenha acesso ao estado, você deve especificar explicitamente em qual estado o componente terá acesso. Seu componente não terá acesso ao estado sem isso.

mapStateToProps é uma função que simplesmente retorna um objeto que define qual estado deve ser passado para o componente, atribuindo valores no estado às propriedades que você define neste objeto. Essencialmente, o objeto que você retorna no mapStateToProps é o que seus objetos estarão em seu componente. A função mapStateToProps é passada para o método de conexão como o primeiro argumento.

O mapStateToProps toma o estado inteiro como um parâmetro e você pega apenas o que você precisa dele. Aqui, porém, como nosso estado contém apenas a lista de todos. Precisamos dessa lista no nosso componente ToDo, vamos retornar o estado inteiro como uma propriedade chamada todos.

Nossa definição de mapStateToProps que simplesmente atribui o estado inteiro a um objeto chamado

Como você pode ver agora, temos acesso a toda a nossa lista de todos em nossos adereços como this.props.todos . Foi assim que conseguimos renderizar todos os nossos todos no exemplo anterior, mapeando-os.

Finalmente, precisamos passar essa função para o nosso método de conexão para conectar tudo.

8. Exporte a função de conexão, passando mapStateToProps e null como os 2 argumentos e passando o nome do componente no segundo par de colchetes

Connect é um método que conecta as funções mapStateToProps e mapDispatchToProps (veja abaixo) ao seu componente, para que a loja possa ler essas funções e garantir que o que você definiu lá seja passado para o componente como props. Este método tem uma sintaxe especial que se parece com isso:

connect(mapStateToProps, MapDispatchToProps)(YourComponent)

Você passa no map...ToProps 2 map...ToProps funciona na conexão e depois o nome do seu componente dentro do segundo par de chaves. Um padrão típico é exportar o método connect em vez do seu componente quando você exporta o componente no final do arquivo. Por exemplo:

export default connect(mapStateToProps, MapDispatchToProps)(YourComponent)

Isso então age da mesma maneira que exportar normalmente, exceto o estado e os despachos serão passados como acessórios. mapStateToProps e mapDispatchToProps são params opcionais para se conectar. Se você não quiser passar um ou outro, coloque nulo no lugar deles.

Você pode estar se perguntando de onde essa função mapDispatchToProps veio e por que não a mencionamos em nenhum lugar antes aqui. Bem, como este guia é o exemplo mais simplificado de um repositório do Redux e o mapDispatchToProps não é estritamente obrigatório, eu não o incluí no nosso exemplo. Se você não passar mapDispatchToProps e passar null ao invés disso, você ainda pode acessar a função de despacho em seu componente como nós temos anteriormente como this.props.dispatch .

Então, para finalizar nosso aplicativo de exemplo, tudo o que precisamos fazer é exportar nosso componente com a função connect e passar o mapStateToProps que acabamos de definir.

Nós exportamos nosso componente envolvendo-o com o método connect e passando nossa função mapStateToProps

E é isso! Essa é uma implementação completa de uma loja Redux. Veja abaixo o exemplo prático do que implementamos.

Exemplo de Código Anotado Completo

App.js

Código completo para o arquivo App.js

Todo.js

Código completo para o arquivo Todo.js

Espero que este guia possa simplificar alguns dos detalhes estranhos e às vezes confusos do Redux. Não é um guia completo do Redux, pois há definitivamente mais elementos e padrões para entender. Mas se você pode entender este guia, então você está no caminho certo para poder trabalhar com e instalar o Redux em seus aplicativos.