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.
npx create-react-app newApp
Passo 2: Installa Redux Thunk
Esegui il seguente comando per installare Redux Thunk.
npm install redux-thunk
Passo 3: Abilita il 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;
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:
// 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.
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.
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
:
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:
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 onTransition
, actions
, 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