Middleware do React: Conectando APIs e Componentes

Middleware não é um conceito novo no desenvolvimento web. Geralmente está associado a frameworks backend como o Express.js, onde há muita autenticação, logging, etc. Devido às suas vantagens inerentes, o middleware ganhou 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 guiá-lo pelo conceito de middleware no React e como utilizá-lo para aprimorar a funcionalidade de sua aplicação React e gerenciar o fluxo da aplicação de forma eficaz.

Ao final, você terá um bom entendimento do que é o middleware no React e como implementá-lo com o Redux Thunk.

Simplificando o Middleware no React: Otimizando a Lógica da Aplicação

O Que É Middleware?

Como o próprio nome sugere, o middleware é uma camada que fica entre diferentes componentes de uma aplicação. Ele fornece uma camada de processamento e funcionalidade onde não haveria uma sem ele. O middleware funciona interceptando requisições que fluem de um componente para outro e permite que você realize ações específicas. Uma vez feito, ele passa a requisição modificada para o próximo middleware ou seu destino pretendido.

Este é um conceito principalmente usado no backend. No entanto, como mencionado anteriormente, ele foi adaptado no React para servir a um propósito semelhante. Agora, vamos mergulhar no que o middleware significa, 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 que você as define. Cada função tem acesso ao estado e ações do aplicativo. Portanto, as funções podem modificar e despachar novas ações.

Quando o estado muda no React, o aplicativo despacha ações que são então manipuladas pelo(s) Reducer(s). O(s) Reducer(s) então retornará um novo estado, que é então armazenado e passado de volta para o aplicativo.

O middleware do React fica entre a ação despachada e a intercepta antes de chegar ao redutor. Em seguida, permite que você se conecte a esse processo e execute algum código nesta ação, por exemplo, registrando-a ou fazendo uma chamada de API.

Uma vez feito isso, ele passará a ação modificada para o Redutor (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 – vamos nos aprofundar em como usar este middleware para modificar uma ação.
  • Saga.

Cada um deles lida com diferentes tipos de modificações em ações, como veremos abaixo ao analisarmos os usos de middleware no React. Outras bibliotecas do React, como React Query, também usam middleware (mais sobre isso depois).

Antes de vermos como implementar isso, vamos analisar os diferentes usos de middleware no React.

Usos de Middleware no React

O middleware do React é útil para os seguintes casos de uso:

Depuração e Registro de Logs

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, esses registros podem ser úteis para identificar possíveis bugs e erros para resolução precoce.

O Redux Logger (para Redux) pode ajudar nisso. Ele registra ações Redux e mudanças de estado para facilitar a depuração. 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ê deseja autenticar usuários antes de atualizar o estado, pode usar Redux Thunk ou Saga para lidar com os fluxos de autenticação. Uma vez que você intercepta 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 rota específica ou não.

Operações Orientadas por Eventos

O redutor 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 redutor assim que isso for feito.

Armazenamento em Cache de Dados

O React Query (outro middleware do React) pode servir como uma ferramenta eficaz na cache de dados da aplicação. Ele armazena em cache automaticamente as respostas da API e as revalida quando necessário. Como resultado, ele 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 processamento em lote de 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 de forma eficaz.

O Que É Thunk?

Na programação em geral, um “Thunk” é simplesmente uma função usada para adiar a avaliação e execução de outra função. Podemos vê-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 a loja Redux quando a operação estiver completa.

Nota: O Redux Thunk permite operações tanto assíncronas quanto síncronas, embora seu propósito principal seja facilitar ações assíncronas. 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 um middleware Redux envolve os seguintes passos:

Passo 1: Configurar o Redux Com Thunk

Crie um aplicativo React e instale as dependências.

Plain Text

 

npx create-react-app newApp

Passo 2: Instalar o Redux Thunk

Execute o seguinte comando para instalar o Redux Thunk.

Plain Text

 

npm install redux-thunk

Passo 3: Habilitar o Middleware Thunk

JavaScript

 

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;

Nota: Ao usar o Redux Toolkit, não é necessário instalar explicitamente o thunk.

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:

JavaScript

 

// 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.

JavaScript

 

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 de um Componente

Use o gancho useDispatch para despachar thunks em projetos React.

JavaScript

 

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 lógica de alto nível para funções assíncronas, despacha-as e lida prontamente com erros. Por favor, note que, como isso fornece uma abstração para os casos 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:

JavaScript

 

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:

JavaScript

 

dispatch(dataFetch ());

Usos do Middleware React – Redux Thunk

Thunks podem ser usados para uma variedade de propósitos, incluindo, mas não se limitando a:

  • Abstrair lógicas complexas dos componentes. 
  • Fazer solicitações e lógicas assíncronas. 
  • Escrever funções para despachar múltiplas 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 do que é 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 observar mudanças no estado do MobX e reagir a elas. Dessa forma, o MobX fornece maneiras de lidar com efeitos colaterais, registro e outras tarefas que o middleware normalmente manipula no Redux.

Recoil

O Recoil não suporta middleware da mesma maneira que o Redux, pois 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 usa seletores – estados derivados dependendo de átomos ou de 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 um comportamento semelhante ao middleware usando ganchos como onTransitionactions, e services. Esses ganchos ajudam a interceptar e modificar transições de estado.

Conclusão

Os middlewares atuam como uma ponte para conectar e combinar diferentes componentes de uma aplicação web para melhor fluxo e manipulação de dados. Eles têm sido amplamente utilizados no backend desde então, mas agora também encontraram casos de uso no frontend.

No React, existem várias maneiras de implementar o middleware. Eles geralmente estão 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, na biblioteca Redux, e o Redux Thunk. Também abordamos 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