Os middlewares não são um conceito novo no desenvolvimento web. Eles são tipicamente associados a frameworks de backend como o Express.js, onde há muita autenticação, logging, etc. Devido às suas vantagens inerentes, os middlewares ganharam significativa tração no frontend.
Frameworks frontend como o React estão adotando-o como uma forma de lidar com funcionalidades complexas durante o gerenciamento de estado. Neste guia, vamos te orientar sobre o conceito de middlewares no React e como utilizá-los para aprimorar a funcionalidade do seu aplicativo React e gerenciar o fluxo da aplicação de forma eficaz.
Ao final, você terá um bom entendimento do que é um middleware no React e como implementá-lo com o Redux Thunk.
React Middleware Simplificado: Simplificando a Lógica da Aplicação
O que é um Middleware?
Como o nome sugere, um middleware é uma camada que fica entre diferentes componentes de uma aplicação. Ele fornece uma camada de processamento e funcionalidade quando não haveria uma sem ele. O Middleware funciona interceptando solicitações que fluem de um componente para outro e permite que você execute ações específicas. Uma vez feito isso, ele passa a solicitação modificada para o próximo middleware ou seu destino pretendido.
Este é um conceito principalmente utilizado no backend. No entanto, como mencionado anteriormente, ele foi adaptado no React para servir a um propósito semelhante. Agora, vamos nos aprofundar no que significa middleware, especificamente no React.
Middleware no React
No React, o middleware é implementado como uma série de funções, executadas uma após a outra, na ordem em que você as define. Cada função tem acesso ao estado e às ações do aplicativo. Portanto, as funções podem modificar e despachar novas ações.
Quando o estado muda no React, a aplicação despacha ações que são então tratadas pelo(s) Reducer(s). O(s) Reducer(s) retornará um novo estado, que é armazenado e passado de volta para a aplicação.
O middleware do React fica entre a ação despachada e a intercepta antes que ela chegue ao reducer. Em seguida, permite que você se conecte a esse processo e execute algum código nessa ação, por exemplo, registrando-a ou fazendo uma chamada de API.
Uma vez feito isso, ele passará a ação modificada para o Reducer (se não houver outro middleware na cadeia).
Exemplos de Middleware no React
Você pode encontrar middleware do React principalmente no Redux, a biblioteca complexa de gerenciamento de estado do React. O Redux tem dois tipos principais de middleware:
- Thunk – nós vamos nos aprofundar em como usar esse middleware para modificar uma ação.
- Saga.
Cada um deles lida com diferentes tipos de modificações nas ações, como veremos abaixo ao olharmos para os usos do middleware no React. Outras bibliotecas do React, como o React Query, também utilizam middleware (mais sobre isso mais tarde).
Antes de olharmos como implementar isso, vamos revisar os diferentes usos do middleware no React.
Usos do Middleware no React
Middleware do React é útil para os seguintes casos de uso:
Depuração e Registro
O middleware do React pode ser usado para registrar informações como estado atual, ações e outros dados durante o desenvolvimento da aplicação. Além disso, isso pode ser útil para identificar possíveis bugs e erros para resolução antecipada.
O Redux Logger (para Redux) pode ajudá-lo a fazer isso. Ele registra ações e mudanças de estado do Redux para uma depuração fácil. Ele intercepta cada ação despachada e registra o estado anterior, a ação e o próximo estado.
Autorização e Autenticação
Se você quiser autenticar usuários antes de atualizar o estado, pode usar Redux Thunk ou Saga para gerenciar os fluxos de trabalho de autenticação. Assim que você interceptar uma ação, esse middleware permite que você armazene tokens, verifique a autenticação antes de despachar a ação ou atualize tokens.
Em outras palavras, esses middlewares são úteis para verificar se um usuário está autenticado para acessar uma determinada rota ou não.
Operações Orientadas a Eventos
O reducer do React é projetado para executar código síncrono. Isso significa que, se você tentar executar algo assíncrono nele, não funcionará. Com middlewares do React como Redux Thunk, você pode capturar a ação, realizar tarefas assíncronas como fazer uma chamada de API e prosseguir para o reducer uma vez que isso seja feito.
Cache de Dados
O React Query (outro middleware do React) pode ser uma ferramenta eficaz para o cache de dados da aplicação. Ele armazena em cache as respostas da API automaticamente e as revalida quando necessário. Como resultado, ajuda a evitar chamadas redundantes à API verificando as informações necessárias no cache.
Melhoria de Desempenho
O middleware do React também pode ajudar a melhorar o desempenho da aplicação, adiando ações desnecessárias para mais tarde, debouncing de eventos e processando em lote determinadas tarefas. Ao armazenar em cache as respostas da API, o React Query também melhora o desempenho de seus aplicativos React.
Como Usar Middleware no React?
O Redux é uma ferramenta poderosa para gerenciar o estado global em aplicativos React. Ele inclui vários middlewares em seu conjunto de ferramentas que você pode usar para adicionar funcionalidades personalizadas aos seus aplicativos React. Um dos mais comuns é Redux Thunk.
Introdução ao Redux Thunk
Antes de mergulhar na implementação do Thunk, vamos reunir algumas informações sobre ele para que possamos usá-lo efetivamente.
O Que É Thunk?
Na programação em geral, um “Thunk” é simplesmente uma função usada para adiar a avaliação e execução de uma função. Podemos considerá-lo como uma função que adia uma ação até que uma condição específica seja atendida.
No Redux, um thunk é uma função específica usada com o middleware Redux Thunk. O Redux Thunk é projetado para permitir operações assíncronas em seu aplicativo React. Anteriormente mencionamos que o Reducer é construído para executar código síncrono. Isso significa que quando uma ação é despachada, o redutor atualiza o estado imediatamente.
Redux Thunk como Middleware
O Redux Thunk atua como middleware. Ele permite que você escreva criadores de ação que retornam funções (thunks) em vez de objetos de ação simples. Essas funções podem conter lógica assíncrona. Quando você despacha um thunk, o middleware Thunk o intercepta e executa a função.
Dentro do thunk
, você pode realizar sua operação assíncrona (por exemplo, fazer uma chamada de API) e depois despachar ações regulares para atualizar o armazenamento Redux quando a operação estiver concluída.
Observação: O Redux Thunk permite tanto operações assíncronas quanto síncronas, embora seu propósito principal seja facilitar ações assíncronas. Ele não impede você de despachar ações síncronas; ele simplesmente fornece um mecanismo para lidar também com as assíncronas.
Com isso esclarecido, vamos ver o middleware React em ação implementando o Redux Thunk.
Um Guia Passo a Passo para Implementar o Redux Thunk
Implementar middleware Redux envolve os seguintes passos:
Passo 1: Configurar o Redux Com Thunk
Crie uma aplicação React e instale as dependências.
npx create-react-app newApp
Passo 2: Instalar Redux Thunk
Execute o seguinte comando para instalar o Redux Thunk.
npm install redux-thunk
Passo 3: Habilitar o Middleware Thunk
Enable the Thunk middleware in the Redux store.
import { configureStore } from '@reduxjs/toolkit';
import thunk from 'redux-thunk';
import rootReducer from './reducers'; // Combine all reducers here
const store = configureStore({
reducer: rootReducer,
middleware: [thunk],
});
export default store;
Observação: Ao usar o Redux Toolkit, não há necessidade de instalar thunk
explicitamente.
Passo 4: Escrevendo Função Assíncrona
Um thunk retorna outra função que recebe os argumentos dispatch
e getState
para ler o estado ou despachar ações. O seguinte é um exemplo de código para buscar dados:
// Tipos de Ação
const START_FETCH = 'START_FETCH';
const FETCH_SUCCESS = 'FETCH_SUCCESS';
const FETCH_ERROR = 'FETCH_ERROR';
// Criadores de Ação
const startFetch = () => ({ type: START_FETCH });
const fetchSuccess = (data) => ({ type: FETCH_SUCCESS, payload: data });
const fetchError = (error) => ({ type: FETCH_ERROR, payload: error });
// Ação de Thunk
export const fetchData = () => {
return async (dispatch, getState) => {
dispatch(startFetch()); // Notify that the fetch has started
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!response.ok) {
throw new Error('Failed to fetch data');
}
const data = await response.json();
dispatch(fetchSuccess(data)); // Send the fetched data to the store
} catch (error) {
dispatch(fetchError(error.message)); // Handle any errors
}
};
};
Passo 5: Lidando com Ações Despachadas no Redutor
Lide com as ações despachadas atualizando o redutor.
const initialState = {
data: [],
isLoading: false,
error: null,
};
export const dataReducer = (state = initialState, action) => {
switch (action.type) {
case START_FETCH:
return { ...state, isLoading: true, error: null };
case FETCH_SUCCESS:
return { ...state, isLoading: false, data: action.payload };
case FETCH_ERROR:
return { ...state, isLoading: false, error: action.payload };
default:
return state;
}
};
Passo 6: Despachando Thunk a partir de um Componente
Use o gancho useDispatch
para despachar thunks em projetos React.
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchData } from './actions';
const DataComponent = () => {
const dispatch = useDispatch();
const { data, isLoading, error } = useSelector((state) => state.data);
useEffect(() => {
dispatch(fetchData()); // Trigger the thunk to fetch data
}, [dispatch]);
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return (
<ul>
{data.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
);
};
export default DataComponent;
Usando createAsyncThunk
O Redux Toolkit contém uma API integrada que define a lógica de alto nível para funções assíncronas, as despacha e lida prontamente com erros. Por favor, note que como isso fornece uma abstração para os casos de uso específicos de funções assíncronas, createAsyncThunk
não se aplica a todos os casos de uso de thunks.
O seguinte é um exemplo de implementação do createAsyncThunk
:
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
export const dataFetch = createAsyncThunk('data/fetchData', async () => {
const response = await fetch('https://api.example.com/data');
return response.json();
});
const dataSlice = createSlice({
name: 'data',
initial_State: { data: [], loading: false, error: null },
extraReducers: (builder) => {
builder
.addCase(dataFetch.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(dataFetch.fulfilled, (state, action) => {
state.loading = false;
state.data = action.payload;
})
.addCase(dataFetch.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message;
});
},
});
export default dataSlice.reducer;
Agora, para despachar o thunk dataFetch
, use o seguinte código:
dispatch(dataFetch ());
Usos de Middleware React – Redux Thunk
Thunks podem ser usados para uma variedade de propósitos, incluindo, mas não se limitando a:
- Abstrair lógica complexa dos componentes.
- Realizar solicitações e lógica assíncrona.
- Escrever funções para despachar várias ações em série.
Middleware do React em Outras Bibliotecas de Gerenciamento de Estado
O Redux não é a única biblioteca do React que utiliza middleware. Você também pode encontrá-los em outras bibliotecas de gerenciamento de estado, embora a implementação desse conceito nessas bibliotecas seja diferente de como é feito no Redux.
MobX
O MobX não possui middleware tradicional como o Redux. Ele oferece funcionalidades semelhantes por meio de mecanismos como interceptadores, observadores e reações. Esses mecanismos permitem que você observe as alterações em seu estado MobX e reaja a elas. Dessa forma, o MobX fornece maneiras de lidar com efeitos colaterais, registro e outras tarefas que middleware tipicamente trata no Redux.
Recoil
O Recoil não suporta middleware da mesma maneira que o Redux porque não precisa. Ele permite que você atualize diretamente partes do estado (átomos) usando funções específicas. Não há despacho de ações para um redutor, que pode ser interceptado com middleware. Para lidar com operações assíncronas, ele utiliza seletores – estados derivados dependendo de átomos ou outros seletores.
Zustand
Ele ajuda a gerenciar estados com uma API simples e suporta middleware nativo para registro e armazenamento de estados, assim como o Redux.
XState
O XState suporta comportamento semelhante a middleware usando hooks como onTransition
, actions
, e services
. Esses hooks ajudam a interceptar e modificar transições de estado.
Conclusão
Middleware atua como uma ponte para conectar e combinar diferentes componentes de uma aplicação web para um melhor fluxo e manipulação de dados. Eles têm sido amplamente utilizados no backend desde então, mas agora encontraram casos de uso também no frontend.
No React, existem várias maneiras de implementar o middleware. Eles estão geralmente ligados às bibliotecas de gerenciamento de estado, como Redux e MobX. O middleware do React mais comumente usado, Thunk, está incluído na biblioteca Redux. Um thunk é um bloco de código que executa tarefas atrasadas.
Neste artigo, exploramos o Middleware no React, biblioteca Redux e Redux Thunk. Também cobrimos os passos para implementar o middleware Redux Thunk para buscar dados e despachar ações.
Source:
https://dzone.com/articles/demystifying-react-middleware-bridging-apis-and-co