POR QUE e COMO USAR o Redux??
Tags: redux, react, nextjs, frontend
Published: 2023-05-31 13:50:16

_Redux com Toolkit no ReactJS/NextJS_

## Quer aprender apenas analisando um código?
Vá ao repositório: _https://github.com/aldcejam/Tutorial_Redux-toolkit_
> _O README do projeto diz quais os arquivos necessários para que o Redux funcione_
Os commits do projeto seguem a sequência deste tutorial pós instalação

## Os porquês:

1. Organização do estado: O Redux ajuda a manter todas as informações importantes do seu aplicativo organizadas em um só lugar, facilitando o controle e a compreensão.
2. Fluxo de dados controlado: Com o Redux, você tem um fluxo de dados bem definido, o que torna mais fácil entender como as coisas funcionam e evita problemas inesperados.
3. Escalabilidade: Se o seu aplicativo está ficando grande e complexo, o Redux oferece uma maneira de gerenciar tudo de forma mais estruturada, facilitando a manutenção e o desenvolvimento contínuo.
4. Compatibilidade com outras bibliotecas: O Redux é amplamente utilizado em projetos JavaScript e funciona bem com várias bibliotecas e frameworks populares, como React, Angular e Vue.js.
5. Ferramentas para desenvolvedores: O Redux oferece ferramentas que ajudam no desenvolvimento, depuração e monitoramento do estado do aplicativo, tornando o processo mais fácil e eficiente.

> ADENDO: Não é preciso utilizar o Redux para gerenciar todos os estados globais da sua aplicação. Se você tiver um caso simples, como configurar o tema do seu aplicativo, recomendo usar o Context do React.



## Como usar:

### Etapa 1: Instalação
yarn:
```
yarn add react-redux @reduxjs/toolkit
```
_npm_

```
npm install react-redux @reduxjs/toolkit
```


### Etapa 2: Configurações:
Crie uma pasta para conter os arquivos hook.ts e o store.ts do Redux

```
|-- src
    |-- redux.config
        |-- hook.ts
        |-- store.ts
```


Arquivo hook.ts

> Este arquivo será responsável pela tipagem dos estados do Redux.
```
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'
 
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
```

Arquivo store.ts

> Este arquivo será responsável por centralizar os estados Redux.
Neste arquivo você só precisa entender que cada item em reducer é um Estado Redux, ou seja, cada novo estado redux que criar, o adicione no objeto reducer.


```
import { configureStore,ThunkAction,Action } from '@reduxjs/toolkit' 
/* import EstadoRedux from "caminho" */

export const Store = configureStore({
  reducer: {
    /* NomeDoEstado: EstadoRedux, */
  },
});

export type AppDispatch = typeof Store.dispatch;
export type RootState = ReturnType<typeof Store.getState>;
export type AppThunk<ReturnType = void> = ThunkAction<
  ReturnType,
  RootState,
  unknown,
  Action<string>
>;
```

**Agora vamos configurar o provider para que todos os nossos componentes e páginas possam acessar os estados do Redux.**

> caso não esteja utilizando o diretório app com layouts do NextJS 
 versão 13+, apenas coloque o provider no arquivo _app.ts.

o layout pai de todos ficará assim:

```
"use client"
import { Provider } from 'react-redux'
import { Store } from '@/redux.config/store'
import './globals.css' 
 

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="pt-br">
      <Provider store={Store}>
        <body>{children}</body>
      </Provider>
    </html>
  )
}

```


###Etapa 3: Criar estado redux

O nome do estado será "ShoppingCartData" e terá dois estados, um de string ID e outro de objeto com itens de compra e sua quantidade.

```
{
   id: string
   itens: {
      carne: string
      arroz: string
   }
}
```
_Siga estas etapas para se manter organizado:_
1. Vamos criar a pasta @core em src para centralizar os estados
2. Vamos criar uma pasta com o nome do nosso estado
4. Agora vamos criar um arquivo ShoppingCartData.ts e ShoppingCartData.d.ts para a tipagem

```
|-- src
    |-- @core
        |-- ShoppingCartData
            |-- ShoppingCartData.ts
            |-- IShoppingCartData.d.ts
```

no arquivo **ShoppingCartData.ts** podemos fazer o seguinte código inicial padrão:

```
import { RootState } from "@/redux.config/store";
import { createSlice, PayloadAction } from "@reduxjs/toolkit";

const initialState = {

}

export const ShoppingCartDataSlice = createSlice({
    name: "ShoppingCartData",
    initialState,
    reducers: {
    }
})

export const { } = ShoppingCartDataSlice.actions

export const ShoppingCartDataStates = (state: RootState) => state.ShoppingCartData

export default ShoppingCartDataSlice.reducer
```

> O objeto InitialStates é o responsável por ter todos os estados deste Redux
  O objeto reducers será o responsável por ter todos os _setState_ dos estados em InitialStates

Agora para fazer toda tipagem para o arquivo ShoppingCartData.ts vamos usar o arquivo _**IShoppingCartData.d.ts**_. Dado os estados previamente previstos temos a seguinte tipagem:

```
type IDProps = string
type ShoppingCartItemsProps = {
    [itemName: string]: string;
}

interface IShoppingCartDataProps {
    ID: IDProps;
    shoppingCartItems: ShoppingCartItemsProps;
}

export { IShoppingCartDataProps, IDProps, ShoppingCartItemsProps}
```

> A tipagem dos itens de IShoppingCartDataProps não são atoa, brevemente você entenderá o motivo.

Agora, com a tipagem estabelecida podemos adicionar os estados de initialStates e os reducers no nosso arquivo ShoppingCartData.ts

```
import { RootState } from "@/redux.config/store";
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { IDProps, IShoppingCartDataProps, ShoppingCartItemsProps } from "./IShoppingCartData"

const initialState: IShoppingCartDataProps = {
    ID: "" as IDProps,
    shoppingCartItems: {} as ShoppingCartItemsProps
}

export const ShoppingCartDataSlice = createSlice({
    name: "ShoppingCartData",
    initialState,
    reducers: {
        setID: (state, action: PayloadAction<IDProps>) => {
            state.ID = action.payload
        },
        setShoppingCartItems: (state, action: PayloadAction<ShoppingCartItemsProps>) => {
            state.shoppingCartItems = action.payload
        }
    }
})

export const {
    setID,
    setShoppingCartItems

} = ShoppingCartDataSlice.actions

export const ShoppingCartDataStates = (state: RootState) => state.ShoppingCartData

export default ShoppingCartDataSlice.reducer
```

> Perceba as seguintes etapas
etapa 1: importação das tipagens do arquivo ShoppingCartData.d.ts.
etapa 2: atribuição da tipagem "IShoppingCartDataProps" em InitialStates.
etapa 3: implementação de valores iniciais para os estados de InitialStates (agora obrigatórios devido a tipagem).
etapa 4: criação dos reducers para cada item de InitialStates. Perceba que tipamos o valor a ser recebido na função set quando colocamos "action: PayloadAction< IDProps>", logo, o state a ser passado para o setID terá que ser um valor do tipo IDProps.
etapa 5: para finalizar exportamos os Set do reducers

**para finalizar a etapa 3 podemos importar nosso ShoppingCartData para o store.ts. O arquivo ficará assim:**
store.ts:

```
import ShoppingCartData from '@/@core/ShoppingCartData/ShoppingCartData';
import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit'


export const Store = configureStore({
    reducer: {
        ShoppingCartData,
    },
});

export type AppDispatch = typeof Store.dispatch;
export type RootState = ReturnType<typeof Store.getState>;
export type AppThunk<ReturnType = void> = ThunkAction<
    ReturnType,
    RootState,
    unknown,
    Action<string>
>;
```

> O ShoppingCartData importado é o export default do arquivo ShoppingCartData.ts

### Etapa 4: Como MODIFICAR e CONSUMIR os estados

**Consumir:**

```
"use client"
import { ShoppingCartDataStates } from '@/@core/ShoppingCartData/ShoppingCartData'
import { useAppSelector } from '@/redux.config/hook'

const id = useAppSelector(ShoppingCartDataStates).ID
const shoppingCartItems = useAppSelector(ShoppingCartDataStates).shoppingCartItems
```
**Modificar:**

```
"use client"
import { setID, setShoppingCartItems } from '@/@core/ShoppingCartData/ShoppingCartData'
import { useAppDispatch } from '@/redux.config/hook'

const dispatch = useAppDispatch();
const modificarID = ()=> dispatch(setID("999"))
const modificarShoppingCartItems = () => dispatch(setShoppingCartItems({
    carne: "2kg",
    arroz: "1kg"
}))
```