El middleware no es un concepto nuevo en el desarrollo web. Normalmente se asocia con frameworks backend como Express.js, donde hay mucha autenticación, registro, etc. Debido a sus ventajas inherentes, el middleware ha ganado una gran popularidad en el frontend.
Frameworks frontend como React lo están adoptando como una forma de manejar funcionalidades complejas durante la gestión de estado. En esta guía, te guiaremos a través del concepto de middleware en React y cómo usarlo para mejorar la funcionalidad de tu aplicación React y gestionar el flujo de la aplicación de manera efectiva.
Al final, tendrás un buen entendimiento de qué es el middleware en React y cómo implementarlo con Redux Thunk.
Middleware en React Simplificado: Simplificando la Lógica de la Aplicación
¿Qué es el Middleware?
Como su nombre sugiere, el middleware es una capa que se sitúa entre diferentes componentes de una aplicación. Proporciona una capa de procesamiento y funcionalidad aquí cuando de otra forma no existiría. El middleware funciona interceptando las peticiones que fluyen de un componente a otro y te permite realizar acciones específicas. Una vez hecho esto, pasa la petición modificada al siguiente middleware o a su destino previsto.
Este es un concepto utilizado principalmente en el backend. Pero, como se mencionó anteriormente, se ha adaptado en React para servir un propósito similar. Ahora, vamos a adentrarnos en lo que significa el middleware, específicamente en React.
Middleware en React
En React, un middleware se implementa como una serie de funciones, ejecutadas una tras otra, en el orden que las defines. Cada función tiene acceso al estado y acciones de la aplicación. Por lo tanto, las funciones pueden modificar y despachar nuevas acciones.
Cuando el estado cambia en React, la aplicación despacha acciones que luego son manejadas por el Reducer (o Reductores). El Reducer (o Reductores) devolverá entonces un nuevo estado, que se almacena y se pasa de nuevo a la aplicación.
El middleware de React se sitúa entre la acción despachada e intercepta la antes de llegar al reductor. Luego, te permite enganchar en este proceso y ejecutar algún código en esta acción, por ejemplo, registrándola o haciendo una llamada a una API.
Una vez hecho esto, pasará la acción modificada al Reductor (si no hay otro middleware en la cadena).
Ejemplos de Middleware en React
Puedes encontrar middleware de React principalmente en Redux, la biblioteca de gestión de estado complejo de React. Redux tiene dos tipos principales de middleware:
- Thunk: profundizaremos en cómo usar este middleware para modificar una acción.
- Saga.
Cada uno de ellos maneja diferentes tipos de modificaciones a las acciones, como veremos a continuación al analizar los usos de middleware en React. Otras bibliotecas de React, como React Query, también utilizan middleware (más sobre esto más adelante).
Antes de ver cómo implementar esto, repasemos los diferentes usos del middleware en React.
Usos del Middleware en React
El middleware de React es útil para los siguientes casos de uso:
Depuración y Registro
El middleware de React se puede usar para registrar información como el estado actual, acciones y otros datos durante el desarrollo de la aplicación. Además, esto puede ser útil para identificar posibles errores y fallos para una resolución temprana.
El Redux Logger (para Redux) puede ayudarte a hacer esto. Registra las acciones y los cambios de estado de Redux para facilitar la depuración. Intercepta cada acción despachada y registra el estado anterior, la acción y el siguiente estado.
Autorización y Autenticación
Si deseas autenticar a los usuarios antes de actualizar el estado, puedes usar Redux Thunk o Saga para manejar los flujos de trabajo de autenticación. Una vez que interceptas una acción, este middleware te permite almacenar tokens, verificar la autenticación antes de despachar la acción o refrescar los tokens.
En otras palabras, estos middleware son útiles para verificar si un usuario está autenticado para acceder a una ruta particular o no.
Operaciones Basadas en Eventos
El reductor de React está diseñado para ejecutar código sincrónico. Esto significa que si intentas ejecutar algo asincrónico en él, no funcionará. Con middleware de React como Redux Thunk, puedes capturar la acción, realizar tareas asincrónicas como hacer una llamada a la API, y proceder al reductor una vez que esto esté hecho.
Almacenamiento en Caché de Datos
React Query (otro middleware de React) puede servir como una herramienta efectiva en el almacenamiento en caché de datos de la aplicación. Almacena en caché las respuestas de la API automáticamente y las revalida cuando sea necesario. Como resultado, te ayuda a evitar llamadas redundantes a la API al buscar la información requerida en la caché.
Mejora del rendimiento
El middleware de React también puede ayudar a mejorar el rendimiento de la aplicación al retrasar acciones innecesarias para más tarde, debouncear eventos y procesar en lotes ciertas tareas. Al almacenar en caché las respuestas de la API, React Query también mejora el rendimiento de tus aplicaciones de React.
Cómo usar Middleware en React?
Redux es una herramienta poderosa para gestionar el estado global en aplicaciones de React. Incluye varios middlewares en su conjunto de herramientas que puedes utilizar para añadir funcionalidades personalizadas a tus aplicaciones de React. Uno de los más comunes es Redux Thunk.
Introducción a Redux Thunk
Antes de sumergirnos en la implementación de Thunk, recolectemos algo de información al respecto para poder utilizarlo de manera efectiva.
¿Qué es Thunk?
En la programación general, un “Thunk” es simplemente una función que se utiliza para retrasar la evaluación y ejecución de otra función. Podemos verlo como una función que pospone una acción hasta que se cumpla una condición específica.
En Redux, un thunk es una función específica utilizada con el middleware Redux Thunk. Redux Thunk está diseñado para permitir operaciones asíncronas dentro de tu aplicación de React. Anteriormente mencionamos que el Reducer está construido para ejecutar código sincrónico. Esto significa que cuando se despacha una acción, el reductor actualiza el estado inmediatamente.
Redux Thunk como Middleware
Redux Thunk actúa como middleware. Te permite escribir creadores de acciones que devuelven funciones (thunks) en lugar de objetos de acción simples. Estas funciones pueden contener lógica asíncrona. Cuando despachas un thunk, el middleware Thunk lo intercepta y ejecuta la función.
En el thunk
, puedes realizar tu operación asíncrona (por ejemplo, hacer una llamada a una API) y luego despachar acciones regulares para actualizar el almacén de Redux cuando la operación esté completa.
Nota: Redux Thunk permite tanto operaciones asíncronas como síncronas, aunque su propósito principal es facilitar acciones asíncronas. No te impide despachar acciones síncronas; simplemente proporciona un mecanismo para manejar también las acciones asíncronas.
Con eso fuera del camino, veamos el middleware de React en acción implementando Redux Thunk.
Una Guía Paso a Paso para Implementar Redux Thunk
Implementar un middleware de Redux implica los siguientes pasos:
Paso 1: Configurar Uar Redux Con Thunk
Crea una aplicación de React e instala las dependencias.
npx create-react-app newApp
Paso 2: Instalar Redux Thunk
Ejecuta el siguiente comando para instalar Redux Thunk.
npm install redux-thunk
Paso 3: Habilitar 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: Cuando se utiliza Redux Toolkit, no es necesario instalar thunk
explícitamente.
Paso 4: Escribiendo Función Async
Un thunk devuelve otra función que recibe los argumentos dispatch
y getstate
para leer el estado o despachar acciones. El siguiente es el código de ejemplo para obtener datos:
// Tipos de acción
const START_FETCH = 'START_FETCH';
const FETCH_SUCCESS = 'FETCH_SUCCESS';
const FETCH_ERROR = 'FETCH_ERROR';
// Creadores de acción
const startFetch = () => ({ type: START_FETCH });
const fetchSuccess = (data) => ({ type: FETCH_SUCCESS, payload: data });
const fetchError = (error) => ({ type: FETCH_ERROR, payload: error });
// Acción 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
}
};
};
Paso 5: Manejo de Acciones Despachadas en el Reducer
Maneja las acciones despachadas actualizando el reducer.
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;
}
};
Paso 6: Despachando Thunk Desde un Componente
Usa el hook useDispatch
para despachar thunks en proyectos de 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
El Redux Toolkit contiene una API incorporada que define lógica de alto nivel para funciones async, las despacha y maneja errores de manera oportuna. Ten en cuenta que, dado que esto proporciona una abstracción para los casos de uso específicos de funciones async, createAsyncThunk
no se aplica a todos los casos de uso de thunks.
La siguiente es la implementación de ejemplo de 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;
Ahora, para despachar el thunk dataFetch
, usa el siguiente código:
dispatch(dataFetch ());
Usos de Middleware de React – Redux Thunk
Los thunks pueden ser utilizados para una variedad de propósitos, incluyendo pero no limitado a:
- Abstracción de lógica compleja de los componentes.
- Realizar solicitudes y lógica asíncronas.
- Escribir funciones para despachar múltiples acciones en serie.
Middleware de React en otras bibliotecas de gestión de estado
Redux no es la única biblioteca de React que aprovecha el middleware. También puedes encontrarlos en otras bibliotecas de gestión de estado, aunque la implementación de este concepto en estas bibliotecas es diferente de cómo se hace en Redux.
MobX
MobX no tiene middleware tradicional como Redux. Ofrece funcionalidades similares a través de mecanismos como interceptores, observadores y reacciones. Estos mecanismos te permiten observar los cambios en tu estado de MobX y reaccionar ante ellos. De esta manera, MobX proporciona formas de manejar efectos secundarios, registro y otras tareas que el middleware maneja típicamente en Redux.
Recoil
Recoil no admite middleware de la misma manera que Redux porque no lo necesita. Te permite actualizar directamente partes del estado (átomos) utilizando funciones específicas. No hay envío de acciones a un reductor, que se puede interceptar con middleware. Para manejar operaciones asíncronas, utiliza selectores, que son estados derivados según átomos u otros selectores.
Zustand
Ayuda a gestionar estados con una API simple y admite middleware nativo para registro y almacenamiento de estados, al igual que Redux.
XState
XState admite un comportamiento similar al middleware utilizando ganchos como onTransition
, actions
, y services
. Estos ganchos ayudan a interceptar y modificar transiciones de estado.
Conclusión
El middleware actúa como un puente para conectar y combinar diferentes componentes de una aplicación web para un mejor flujo y manejo de datos. Se ha utilizado ampliamente en el backend desde entonces, pero ahora también ha encontrado casos de uso en el frontend.
En React, hay varias formas de implementar el middleware. Generalmente están vinculados a bibliotecas de gestión de estado como Redux y MobX. El middleware de React más utilizado, Thunk, está incluido en la biblioteca Redux. Un thunk es un bloque de código que realiza tareas retrasadas.
En este artículo, hemos explorado Middleware en React, la biblioteca Redux y Redux Thunk. También cubrimos los pasos para implementar middleware Redux Thunk para obtener datos y despachar acciones.
Source:
https://dzone.com/articles/demystifying-react-middleware-bridging-apis-and-co