Header Ads

Como começar com Redux para JavaScript State Management

Redux é uma ferramenta de gerenciamento de estado, construída especificamente para aplicativos JavaScript do lado do cliente que dependem muito de dados complexos e APIs externas, e oferece ótimas ferramentas de desenvolvedor que facilitam o trabalho com seus dados.

[PUBLICAR]

O que Redux faz?

Simplificando, Redux é um armazenamento de dados centralizado. Todos os dados do seu aplicativo são armazenados em um grande objeto. Os Redux Devtools facilitam a visualização:

Esse estado é imutável, o que é um conceito estranho no início, mas faz sentido por alguns motivos. Se você quiser modificar o estado, deve enviar uma ação, que basicamente leva alguns argumentos, forma uma carga útil e a envia para o Redux. Redux passa o estado atual para uma função redutora, que modifica o estado existente e retorna um novo estado que substitui o atual e dispara uma recarga dos componentes afetados. Por exemplo, você pode ter um redutor para adicionar um novo item a uma lista ou remover ou editar um que já existe.

Fazer dessa maneira significa que você nunca obterá qualquer comportamento indefinido com o estado de modificação do aplicativo à vontade. Além disso, como há um registro de cada ação e do que ela mudou, ele permite a depuração de viagem no tempo, onde você pode rolar o estado do seu aplicativo de volta para depurar o que acontece com cada ação (como um histórico do git).

O Redux pode ser usado com qualquer estrutura de front-end, mas é comumente usado com o React, e é nisso que nos concentraremos aqui. Nos bastidores, o Redux usa a API de contexto do React, que funciona de maneira semelhante ao Redux e é boa para aplicativos simples se você quiser renunciar ao Redux por completo. No entanto, os Devtools do Redux são fantásticos ao trabalhar com dados complexos e, na verdade, são mais otimizados para evitar renderizações desnecessárias.

Se você estiver usando TypeScript, as coisas são muito mais complicadas para que o Redux seja rigidamente digitado. Em vez disso, você vai querer seguir este guia, que usa ações de tipo seguro para lidar com as ações e redutores de uma maneira amigável.

Estruturando seu projeto

Primeiro, você deve definir o layout da sua estrutura de pastas. Isso é com você e as preferências de estilo de sua equipe, mas existem basicamente dois padrões principais que a maioria dos projetos Redux usa. O primeiro é simplesmente dividir cada tipo de arquivo (ação, redutor, middleware, efeito colateral) em sua própria pasta, assim:

 store / actions / reducers / sagas / middleware / index. js 

No entanto, este não é o melhor, já que muitas vezes você precisará de um arquivo de ação e de um redutor para cada elemento adicionado. É melhor mesclar as pastas de ações e redutores e dividi-los por recurso. Desta forma, cada ação e redutor correspondente ficam no mesmo arquivo. Você

 store / features / todo / etc / sagas / middleware / root-reducer. js root-action. js index. js 

Isso limpa as importações, pois agora você pode importar as ações e os redutores na mesma instrução usando:

 importe {todosActions, todosReducer} de 'store / features / todos' 

Depende de você se deseja manter o código Redux em sua própria pasta (/ store nos exemplos acima) ou integrá-lo à pasta raiz src do seu aplicativo. Se você já está separando o código por componente e está escrevendo várias ações personalizadas e redutores para cada componente, convém mesclar as pastas / features / e / components / e armazenar os componentes JSX junto com o código redutor.

Se você estiver usando Redux com TypeScript, poderá adicionar um arquivo adicional em cada pasta de recursos para definir seus tipos.

Instalando e configurando Redux

Instale Redux e React-Redux do NPM:

 npm install redux react-redux 

Você provavelmente também desejará redux-devtools:

 instalação npm --save-dev redux-devtools 

A primeira coisa que você deseja criar é sua loja. Salve como /store/index. js

 importar {createStore} de 'redux' importar rootReducer de './root-reducer' const store = createStore (rootReducer) exportar armazenamento padrão; 

Claro, sua loja ficará mais complicada do que isso à medida que você adiciona coisas como complementos de efeito colateral, middleware e outros utilitários como roteador conectado-reagir, mas isso é tudo o que é necessário por enquanto. Esse arquivo pega o redutor de raiz e chama createStore () usando-o, que é exportado para o aplicativo usar.

A seguir, criaremos um recurso simples de lista de tarefas. Provavelmente, você desejará começar definindo as ações que esse recurso requer e os argumentos que são transmitidos a eles. Crie uma pasta / features / todos / e salve o seguinte como types. js:

 export const ADD = 'ADD_TODO' export const DELETE = 'DELETE_TODO' export const EDIT = 'EDIT_TODO' 

Isso define algumas constantes de string para os nomes das ações. Independentemente dos dados que você está passando, cada ação terá uma propriedade de tipo, que é uma string única que identifica a ação.

Não é necessário ter um arquivo de tipo como este, pois você pode simplesmente digitar o nome da string da ação, mas é melhor para a interoperabilidade fazer isso dessa maneira. Por exemplo, você poderia ter todos. ADD e lembretes. ADD no mesmo aplicativo, o que evita o incômodo de digitar _TODO ou _REMINDER toda vez que você faz referência a uma ação para esse recurso.

A seguir, salve o seguinte como /store/features/todos/actions. js:

 importar * como tipos de './types. js' export const addTodo = text = > ({type: types. ADD, text}) export const deleteTodo = id = > ({type: types. DELETE, id}) export const editTodo = (id, text) = > ({type: types. EDIT, id, text}) 

Isso define algumas ações usando os tipos das constantes de string, exibindo os argumentos e a criação de carga útil para cada um. Eles não precisam ser totalmente estáticos, pois são funções — um exemplo que você pode usar é definir um CUID de tempo de execução para determinadas ações.

O código mais complicado, e onde você implementará a maior parte de sua lógica de negócios, são os redutores. Eles podem assumir várias formas, mas a configuração mais comumente usada é com uma instrução switch que trata cada caso com base no tipo de ação. Salve como reducer. js:

 importar * como tipos de './types. js' const initialState = [{text: 'Hello World', id: 0}] exportar função padrão todos (state = initialState, action) {switch (action . type) {case types. ADD: return [... state, {id: state. reduce ((maxId, todo) = > Math. max (todo. id, maxId), -1) + 1, text: action. text}] case types. DELETE: return state. filter (todo = > todo. id! == action. id) case types. EDIT: return state. map (todo = > todo. id === action . id? {... todo, text: action. text}: todo) default: estado de retorno}} 

O estado é passado como um argumento e cada caso retorna uma versão modificada do estado. Neste exemplo, ADD_TODO anexa um novo item ao estado (com um novo ID a cada vez), DELETE_TODO remove todos os itens com o ID fornecido e EDIT_TODO mapeia e substitui o texto do item pelo ID fornecido.

O estado inicial também deve ser definido e passado para a função redutor como o valor padrão para a variável de estado. Obviamente, isso não define toda a estrutura de estado do Redux, apenas a seção state. todos.

Esses três arquivos são geralmente separados em aplicativos mais complexos, mas se você quiser, também pode defini-los todos em um arquivo, apenas certifique-se de &’ reimportar e exportar corretamente.

Com esse recurso concluído, vamos conectá-lo ao Redux (e ao nosso aplicativo). Em /store/root-reducer. js, importe todosReducer (e qualquer outro redutor de recurso da pasta / features /) e, em seguida, passe-o para combineReducers (), formando um redutor raiz de nível superior que é passado para a loja. É aqui que você configurará o estado raiz, certificando-se de manter cada recurso em seu próprio branch.

 importar {combineReducers} de 'redux'; importar todosReducer de './features/todos/reducer'; const rootReducer = combineReducers ({todos: todosReducer}) exportar rootReducer padrão 

Usando Redux In React

Claro, nada disso é útil se não estiver conectado ao React. Para fazer isso, você terá que envolver todo o seu aplicativo em um componente Provedor. Isso garante que o estado e os ganchos necessários sejam transmitidos a todos os componentes do seu aplicativo.

Em App. js ou index. js, onde quer que você tenha sua função de renderização raiz, envolva seu aplicativo em um < Provider > e passe-o para a loja (importado de /store/index. js) como um prop:

importar React de 'react'; importar ReactDOM de 'react-dom'; // Configuração do Redux import {Provider} from 'react-redux'; loja de importação, {histórico} de './store'; ReactDOM. render (< Provider store = > < App / > < / Provider >, document. getElementById ('root'));

Agora você está livre para usar o Redux em seus componentes. O método mais fácil é com componentes de função e ganchos. Por exemplo, para despachar uma ação, você usará o gancho useDispatch (), que permite chamar ações diretamente, por exemplo, despachar (todosActions. addTodo (texto)).

O contêiner a seguir tem uma entrada conectada ao estado React local, que é usado para adicionar uma nova tarefa ao estado sempre que um botão é clicado:

import React, {useState} de 'react'; import './Home. css'; import {TodoList} de 'componentes' import {todosActions} de 'store / features / todos' import {useDispatch} da função 'react-redux' Home () {const dispatch = useDispatch (); const [text, setText] = useState (""); function handleClick () {dispatch (todosActions. addTodo (texto)); setText (""); } function handleChange (e: React. ChangeEvent < HTMLInputElement >) {setText (e. target. value); } return (< div className = "App" > < header className = "App-header" > < input type = "text" value = onChange = / > < botão onClick = > Adicionar Novo Todo < / button > < TodoList / > < / header > < / div >); } export default Home; Então, quando você quiser fazer uso dos dados armazenados no estado, use o gancho useSelector. Isso leva uma função que seleciona parte do estado para uso no aplicativo. Neste caso, ele define a variável post para a lista atual de todos. Isso é então usado para renderizar um novo item de tarefa para cada entrada em state. todos.

importar React de 'react'; import {useSelector} de 'armazenar' import {Container, List, ListItem, Title} da função './styles' TodoList () {const posts = useSelector (state = > state. todos) return (< Container > < Lista >) = > (< ListItem key = > < Title >: < / Title > < / ListItem >))} < / List > < / Container > ); } exportar TodoList padrão; Você pode criar funções de seletor personalizadas para lidar com isso para você, salvas na pasta / features / da mesma forma que ações e redutores. Uma vez que você tenha tudo configurado e descoberto, você pode querer configurar o Redux Devtools, configurando middleware como Redux Logger ou connected-react-router ou instalando um modelo de efeito colateral como Redux Sagas.

Nenhum comentário