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:
- 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.
- 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.
- 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.
- 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.
- 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:
- Vamos criar a pasta @core em src para centralizar os estados
- Vamos criar uma pasta com o nome do nosso estado
- 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"
}))
Top comments (0)