Middleware React: Collegamento tra API e Componenti

I middleware non è un concetto nuovo nello sviluppo web. È tipicamente associato a framework backend come Express.js, dove c’è molta autenticazione, logging, ecc. A causa dei suoi vantaggi intrinseci, il middleware ha guadagnato notevole trazione nel frontend.

Framework frontend come React lo stanno adottando come modo per gestire funzionalità complesse durante la gestione dello stato. In questa guida, ti guideremo attraverso il concetto di middleware in React e come usarlo per migliorare la funzionalità della tua app React e gestire efficacemente il flusso dell’applicazione.

Alla fine, avrai una buona comprensione di cosa sia il middleware in React e come implementarlo con Redux Thunk.

Middleware React Semplificato: Ottimizzazione della Logica dell’Applicazione

Cos’è il Middleware?

Come suggerisce il nome, il middleware è uno strato che si trova tra diversi componenti di un’applicazione. Fornisce uno strato di elaborazione e funzionalità qui dove non ce ne sarebbe uno senza di esso. Il Middleware funziona intercettando le richieste che fluiscono da un componente all’altro e ti consente di eseguire azioni specifiche. Una volta completato, passa la richiesta modificata al prossimo middleware o alla sua destinazione prevista.

Questo è un concetto principalmente utilizzato nel backend. Ma, come accennato in precedenza, è stato adattato in React per servire uno scopo simile. Ora, immergiamoci in cosa significa il middleware, in particolare in React.

Middleware in React

In React, il middleware è implementato come una serie di funzioni, eseguite una dopo l’altra, nell’ordine in cui le definisci. Ogni funzione ha accesso allo stato e alle azioni dell’app. Pertanto, le funzioni possono modificare e dispatchare nuove azioni.

Quando lo stato cambia in React, l’applicazione dispatcha azioni che vengono poi gestite dal/i Reducer. Il/i Reducer restituiranno quindi un nuovo stato, che verrà memorizzato e passato di nuovo all’applicazione.

Il middleware di React si colloca tra l’azione dispatchata e la intercetta prima che raggiunga il reducer. Poi, ti consente di agganciarti a questo processo ed eseguire del codice su quest’azione, ad esempio, registrandola o effettuando una chiamata API.

Una volta fatto ciò, passerà l’azione modificata al Reducer (se non c’è un altro middleware nella catena).

Esempi di Middleware in React

Puoi trovare il middleware di React principalmente in Redux, la complessa libreria di gestione dello stato per React. Redux ha due principali tipi di middleware:

  • Thunk – approfondiremo come utilizzare questo middleware per modificare un’azione.
  • Saga.

Ciascuno di essi gestisce diversi tipi di modifiche alle azioni, come vedremo più avanti quando esamineremo gli usi del middleware in React. Altre librerie di React, come React Query, utilizzano anch’esse middleware (ne parleremo più avanti).

Prima di esaminare come implementare questo, rivediamo i diversi usi del middleware in React.

Usi del Middleware in React

Il middleware di React è utile per i seguenti casi d’uso:

Debugging e Logging

Il middleware di React può essere utilizzato per registrare informazioni come lo stato attuale, le azioni e altri dati durante lo sviluppo dell’applicazione. Inoltre, può essere utile per individuare potenziali bug ed errori per una risoluzione precoce.

Il Redux Logger (per Redux) può aiutarti in questo. Registra le azioni di Redux e le modifiche di stato per un facile debug. Intercepisce ogni azione inviata e registra lo stato precedente, l’azione e lo stato successivo.

Autorizzazione e Autenticazione

Se desideri autenticare gli utenti prima di aggiornare lo stato, puoi utilizzare Redux Thunk o Saga per gestire i flussi di lavoro di autenticazione. Una volta intercettata un’azione, questo middleware ti consente di memorizzare i token, controllare l’autenticazione prima di inviare l’azione o aggiornare i token.

In altre parole, questi middleware sono utili per verificare se un utente è autenticato per accedere a una determinata rotta o meno.

Operazioni Event-Driven

Il riduttore di React è progettato per eseguire codice sincrono. Ciò significa che se si tenta di eseguire qualcosa in modo asincrono su di esso, non funzionerà. Con middleware di React come Redux Thunk, puoi intercettare l’azione, eseguire attività asincrone come effettuare una chiamata API e procedere al riduttore una volta completato ciò.

Memorizzazione Dati

React Query (un’altra middleware di React) può servire come uno strumento efficace nella memorizzazione nella cache dei dati dell’applicazione. Memorizza automaticamente le risposte API e le riconvalida quando necessario. Di conseguenza, ti aiuta a evitare chiamate API ridondanti controllando le informazioni richieste nella cache.

Miglioramento delle prestazioni

Le middleware di React possono anche aiutare a migliorare le prestazioni dell’applicazione ritardando azioni non necessarie per dopo, debounce di eventi e processare in batch determinati compiti. Memorizzando le risposte API, React Query migliora anche le prestazioni delle tue app React.

Come utilizzare le middleware in React?

Redux è uno strumento potente per gestire lo stato globale nelle applicazioni React. Include diverse middleware nel suo toolkit che puoi utilizzare per aggiungere funzionalità personalizzate alle tue app React. Uno dei più comuni è Redux Thunk.

Introduzione a Redux Thunk

Prima di approfondire l’implementazione di Thunk, raccogliamo alcune informazioni su di esso in modo da poterlo utilizzare efficacemente.

Cos’è Thunk?

Nella programmazione generale, un “Thunk” è semplicemente una funzione che viene utilizzata per ritardare la valutazione e l’esecuzione di una funzione. Possiamo considerarlo come una funzione che posticipa un’azione fino a quando non viene soddisfatta una condizione specifica.

In Redux, un thunk è una funzione specifica utilizzata con la middleware di Redux Thunk. Redux Thunk è progettato per consentire operazioni asincrone all’interno della tua app React. In precedenza abbiamo menzionato che il Reducer è progettato per eseguire codice sincrono. Ciò significa che quando viene inviata un’azione, il reducer aggiorna immediatamente lo stato.

Redux Thunk come Middleware

Redux Thunk funge da middleware. Ti consente di scrivere creatori di azioni che restituiscono funzioni (thunks) invece di semplici oggetti azione. Queste funzioni possono contenere logica asincrona. Quando invii un thunk, il middleware Thunk lo intercetta ed esegue la funzione.

All’interno del thunk, puoi eseguire la tua operazione asincrona (ad esempio, effettuare una chiamata API) e poi inviare azioni normali per aggiornare lo store Redux quando l’operazione è completata.

Nota: Redux Thunk consente sia operazioni asincrone che sincrone, sebbene il suo scopo principale sia facilitare le azioni asincrone. Non preclude l’invio di azioni sincrone; fornisce semplicemente un meccanismo per gestire anche quelle asincrone.

Detto ciò, vediamo il middleware di React in azione implementando Redux Thunk.

Una Guida Passo-Passo per Implementare Redux Thunk

Implementare il middleware Redux implica i seguenti passaggi:

Passo 1: Imposta Redux con Thunk

Crea un’applicazione React e installa le dipendenze.

Plain Text

 

npx create-react-app newApp

Passo 2: Installa Redux Thunk

Esegui il seguente comando per installare Redux Thunk.

Plain Text

 

npm install redux-thunk

Passo 3: Abilita il 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: Quando utilizzi Redux Toolkit, non è necessario installare thunk esplicitamente.

Passo 4: Scrittura della Funzione Asincrona

Un thunk restituisce un’altra funzione che riceve gli argomenti dispatch e getstate per leggere lo stato o inviare azioni. Di seguito è riportato un esempio di codice per il recupero dei dati:

JavaScript

 

// Tipi di azione
const START_FETCH = 'START_FETCH';
const FETCH_SUCCESS = 'FETCH_SUCCESS';
const FETCH_ERROR = 'FETCH_ERROR';

  // Creatori di azioni
const startFetch = () => ({ type: START_FETCH });
const fetchSuccess = (data) => ({ type: FETCH_SUCCESS, payload: data });
const fetchError = (error) => ({ type: FETCH_ERROR, payload: error });

  // Azione 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: Gestione delle Azioni Inviat

Gestire le azioni inviate aggiornando il riduttore.

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: Invio di Thunk da un Componente

Usare il gancio useDispatch per inviare thunks nei progetti 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;

Utilizzo di createAsyncThunk

Il Redux Toolkit contiene un’API integrata che definisce la logica di alto livello per le funzioni asincrone, le invia e gestisce gli errori prontamente. Si noti che poiché fornisce un’astrazione per i casi d’uso specifici delle funzioni asincrone, createAsyncThunk non si applica a tutti i casi d’uso dei thunks. 

Di seguito è riportata un’implementazione di esempio del 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;

Ora, per inviare il thunk dataFetch, utilizzare il seguente codice:

JavaScript

 

dispatch(dataFetch ());

Usi del Middleware React – Redux Thunk

I thunks possono essere utilizzati per una varietà di scopi, tra cui ma non limitati a:

  • Abstracting logiche complesse dai componenti. 
  • Effettuare richieste asincrone e logiche. 
  • Scrivere funzioni per inviare più azioni in serie.

Middleware di React in Altre Librerie di Gestione dello Stato

Redux non è l’unica libreria di React che sfrutta il middleware. Puoi trovarlo anche in altre librerie di gestione dello stato, anche se l’implementazione di questo concetto in queste librerie è diversa rispetto a come viene fatto in Redux.

MobX

MobX non ha un middleware tradizionale come Redux. Offrendo funzionalità simili attraverso meccanismi come intercettori, osservatori e reazioni. Questi meccanismi ti permettono di osservare le modifiche nel tuo stato MobX e reagire ad esse. In questo modo, MobX fornisce modi per gestire effetti collaterali, registrazione e altre attività che il middleware gestisce tipicamente in Redux.

Recoil

Recoil non supporta il middleware nello stesso modo di Redux perché non ne ha bisogno. Ti consente di aggiornare direttamente pezzi di stato (atomi) utilizzando funzioni specifiche. Non c’è l’invio di azioni a un riduttore, che puoi intercettare con il middleware. Per gestire operazioni asincrone, utilizza selettori — stato derivato a seconda degli atomi o di altri selettori.

Zustand

Aiuta a gestire gli stati con una semplice API e supporta middleware nativo per la registrazione e la memorizzazione degli stati, proprio come Redux.

XState

XState supporta un comportamento simile al middleware utilizzando hook come onTransitionactions, e services. Questi hook aiutano a intercettare e modificare le transizioni di stato.

Conclusione

I middleware agiscono come un ponte per collegare e combinare diversi componenti di un’applicazione web per un migliore flusso e gestione dei dati. Sono stati ampiamente utilizzati sul backend fin dall’inizio, ma ora hanno trovato casi d’uso anche sul frontend.

In React, ci sono vari modi per implementare il middleware. Sono di solito collegati alle librerie di gestione dello stato come Redux e MobX. Il middleware React più comunemente usato, Thunk, è incluso nella libreria Redux. Un thunk è un blocco di codice che esegue compiti ritardati.

In questo articolo, abbiamo esplorato il Middleware in React, la libreria Redux e Redux Thunk. Abbiamo anche coperto i passaggi per implementare il middleware Redux Thunk per recuperare dati e inviare azioni.

Source:
https://dzone.com/articles/demystifying-react-middleware-bridging-apis-and-co