Compartir en Twitter
Go to Homepage

GUÍA COMPLETA PARA CREAR MIDDLEWARE EN REDUX

November 30, 2025

Introducción a Redux Middleware

Redux es una biblioteca ampliamente utilizada para la gestión del estado en aplicaciones JavaScript, especialmente en proyectos con React. Su arquitectura basada en un flujo unidireccional de datos permite manejar el estado de manera predecible. Sin embargo, cuando las aplicaciones crecen en complejidad, surge la necesidad de manejar efectos secundarios, como solicitudes HTTP o registros de acciones. Aquí es donde entra en juego el middleware de Redux, una herramienta poderosa que extiende las capacidades de Redux al permitir la intervención en el flujo de despacho de acciones.

En este tutorial, exploraremos qué es el middleware en Redux, cómo funciona y cómo crear uno desde cero. A través de ejemplos prácticos, aprenderás a implementar middleware personalizado para casos como el registro de acciones, el manejo de errores y la integración con APIs. Este contenido está diseñado para desarrolladores que ya tienen conocimientos básicos de Redux y desean profundizar en técnicas avanzadas.

¿Qué es un Middleware en Redux?

Un middleware en Redux es una función que intercepta las acciones antes de que lleguen al reducer. Actúa como un intermediario entre el despacho de una acción y su procesamiento por el reducer, permitiendo ejecutar lógica adicional, como modificar acciones, realizar efectos secundarios o incluso bloquear acciones. Los middlewares son esenciales para manejar tareas asíncronas, como solicitudes a APIs, o para implementar funcionalidades como la gestión de logs.

El flujo típico en Redux sin middleware es simple: una acción se despacha, el reducer la procesa y el estado se actualiza. Con middleware, este flujo se enriquece, ya que puedes agregar lógica personalizada en el proceso. Por ejemplo, un middleware puede registrar cada acción en la consola o realizar una llamada a una API antes de que la acción llegue al reducer.

Estructura de un Middleware

Un middleware en Redux es una función que recibe el store, retorna otra función que recibe el método next, y esta, a su vez, retorna una función que recibe la acción. Esta estructura permite encadenar múltiples middlewares, ya que cada uno puede decidir si pasa la acción al siguiente middleware o la bloquea.

const middleware = (store) => (next) => (action) => {
    // Lógica del middleware
    return next(action); // Pasa la acción al siguiente middleware o al reducer
};

El objeto store proporciona acceso a métodos como getState() y dispatch(). El parámetro next es una función que pasa la acción al siguiente middleware o al reducer. Finalmente, action es el objeto de acción despachado.

Cómo Funciona el Flujo de Middleware

Cuando despachas una acción en Redux, esta pasa por una cadena de middlewares antes de llegar al reducer. Cada middleware puede:

  • Modificar la acción.
  • Ejecutar efectos secundarios, como una solicitud HTTP.
  • Bloquear la acción, evitando que llegue al reducer.
  • Despachar nuevas acciones.

Por ejemplo, un middleware de registro podría verse así:

const loggerMiddleware = (store) => (next) => (action) => {
    console.log("Acción despachada:", action);
    console.log("Estado actual:", store.getState());
    const result = next(action);
    console.log("Nuevo estado:", store.getState());
    return result;
};

En este caso, el middleware registra la acción y el estado antes y después de que la acción sea procesada. La llamada a next(action) asegura que la acción continúe su flujo hacia el siguiente middleware o el reducer.

Creando un Middleware desde Cero

Para ilustrar cómo crear un middleware personalizado, implementaremos uno que maneje solicitudes asíncronas a una API. Este middleware detectará acciones específicas, realizará una llamada HTTP y despachará nuevas acciones según el resultado.

Paso 1: Definir la Acción Asíncrona

Supongamos que queremos cargar datos de una API. Definimos una acción con un tipo específico y un indicador de que es asíncrona:

const FETCH_DATA = "FETCH_DATA";
const FETCH_DATA_SUCCESS = "FETCH_DATA_SUCCESS";
const FETCH_DATA_FAILURE = "FETCH_DATA_FAILURE";

const fetchData = () => ({
    type: FETCH_DATA,
    payload: { url: "https://api.example.com/data" },
});

const fetchDataSuccess = (data) => ({
    type: FETCH_DATA_SUCCESS,
    payload: data,
});

const fetchDataFailure = (error) => ({
    type: FETCH_DATA_FAILURE,
    payload: error,
});

Paso 2: Crear el Middleware

El middleware interceptará la acción FETCH_DATA, realizará la solicitud HTTP y despachará acciones de éxito o error según corresponda.

const apiMiddleware =
    ({ dispatch, getState }) =>
    (next) =>
    (action) => {
        if (action.type !== FETCH_DATA) {
            return next(action);
        }

        const { url } = action.payload;

        fetch(url)
            .then((response) => {
                if (!response.ok) {
                    throw new Error("Error en la solicitud");
                }
                return response.json();
            })
            .then((data) => dispatch(fetchDataSuccess(data)))
            .catch((error) => dispatch(fetchDataFailure(error.message)));

        return next(action);
    };

Este middleware verifica si la acción es de tipo FETCH_DATA. Si no lo es, la pasa al siguiente middleware. Si lo es, realiza la solicitud HTTP y despacha acciones adicionales según el resultado.

Paso 3: Configurar el Store con el Middleware

Para usar el middleware, debemos aplicarlo al store de Redux utilizando applyMiddleware de la biblioteca redux.

import { createStore, applyMiddleware } from "redux";
import rootReducer from "./reducers";

const store = createStore(
    rootReducer,
    applyMiddleware(apiMiddleware, loggerMiddleware)
);

En este ejemplo, el store usa tanto el middleware de API como el de registro. El orden de los middlewares es importante, ya que se ejecutan en la secuencia en que se pasan a applyMiddleware.

Middleware en Redux Toolkit

Redux Toolkit es una biblioteca que simplifica el uso de Redux al proporcionar herramientas como createSlice y configureStore. También facilita la configuración de middlewares. Por defecto, Redux Toolkit incluye middlewares como redux-thunk, que es ideal para manejar acciones asíncronas.

Para agregar un middleware personalizado en Redux Toolkit, puedes usar la opción middleware en configureStore:

import { configureStore } from "@reduxjs/toolkit";
import rootReducer from "./reducers";
import { loggerMiddleware } from "./middleware";

const store = configureStore({
    reducer: rootReducer,
    middleware: (getDefaultMiddleware) =>
        getDefaultMiddleware().concat(loggerMiddleware, apiMiddleware),
});

El método getDefaultMiddleware incluye middlewares preconfigurados como redux-thunk. Puedes concatenar tus middlewares personalizados para extender la funcionalidad.

Casos de Uso Comunes para Middlewares

Los middlewares son extremadamente versátiles y se utilizan para una amplia variedad de tareas. A continuación, exploramos algunos casos comunes con ejemplos.

Registro de Acciones

Un middleware de registro es útil durante el desarrollo para depurar aplicaciones. El siguiente ejemplo muestra un middleware que registra acciones y estados:

const loggerMiddleware =
    ({ getState }) =>
    (next) =>
    (action) => {
        console.log("Acción:", action.type, action.payload);
        console.log("Estado antes:", getState());
        const result = next(action);
        console.log("Estado después:", getState());
        return result;
    };

Manejo de Errores

Un middleware puede capturar errores en las acciones y despachar acciones de error. Por ejemplo:

const errorMiddleware =
    ({ dispatch }) =>
    (next) =>
    (action) => {
        try {
            return next(action);
        } catch (error) {
            dispatch({
                type: "ERROR_OCURRED",
                payload: error.message,
            });
            throw error;
        }
    };

Autorización

Un middleware puede verificar si un usuario está autorizado antes de permitir ciertas acciones:

const authMiddleware =
    ({ getState }) =>
    (next) =>
    (action) => {
        const { user } = getState();
        if (action.type === "RESTRICTED_ACTION" && !user.isAuthenticated) {
            console.warn("Acción restringida: usuario no autenticado");
            return;
        }
        return next(action);
    };

Mejores Prácticas para Crear Middlewares

Crear middlewares efectivos requiere seguir ciertas prácticas para garantizar que sean mantenibles y eficientes:

  1. Mantener la simplicidad: Un middleware debe tener una sola responsabilidad. Por ejemplo, un middleware para solicitudes HTTP no debería manejar también el registro de acciones.

  2. Evitar efectos secundarios innecesarios: Los middlewares deben ser predecibles. Evita modificar el estado global o realizar operaciones que no estén directamente relacionadas con la acción.

  3. Usar nombres descriptivos: Nombra tus middlewares según su función, como apiMiddleware o loggerMiddleware.

  4. Probar los middlewares: Escribe pruebas unitarias para verificar que el middleware maneje correctamente las acciones y los efectos secundarios.

  5. Optimizar el rendimiento: Evita realizar operaciones costosas, como bucles complejos, dentro de un middleware, ya que puede afectar el rendimiento de la aplicación.

Ejemplo de Prueba para un Middleware

Para probar un middleware, puedes usar una biblioteca como Jest. Aquí hay un ejemplo de una prueba para el middleware de registro:

import { loggerMiddleware } from "./middleware";

describe("loggerMiddleware", () => {
    it("registra la acción y pasa al siguiente middleware", () => {
        const store = { getState: jest.fn().mockReturnValue({}) };
        const next = jest.fn();
        const action = { type: "TEST_ACTION" };
        console.log = jest.fn();

        loggerMiddleware(store)(next)(action);

        expect(console.log).toHaveBeenCalledWith(
            "Acción:",
            action.type,
            action.payload
        );
        expect(next).toHaveBeenCalledWith(action);
    });
});

Integración con APIs Modernas

En aplicaciones modernas, es común usar bibliotecas como axios o el API fetch para realizar solicitudes HTTP. Un middleware puede integrarse con estas herramientas para manejar solicitudes asíncronas de manera eficiente.

Por ejemplo, un middleware que usa axios podría verse así:

import axios from "axios";

const axiosMiddleware =
    ({ dispatch }) =>
    (next) =>
    (action) => {
        if (action.type !== "FETCH_DATA_AXIOS") {
            return next(action);
        }

        const { url } = action.payload;

        axios
            .get(url)
            .then((response) =>
                dispatch({ type: "FETCH_DATA_SUCCESS", payload: response.data })
            )
            .catch((error) =>
                dispatch({ type: "FETCH_DATA_FAILURE", payload: error.message })
            );

        return next(action);
    };

Este middleware realiza una solicitud GET con axios y despacha acciones según el resultado.

Depuración y Herramientas

Depurar middlewares puede ser un desafío debido a su naturaleza intermedia. Herramientas como Redux DevTools son imprescindibles para visualizar el flujo de acciones y el estado. Redux DevTools muestra cada acción despachada, el estado antes y después, y los middlewares que las procesaron.

Para habilitar Redux DevTools, configura el store con el enhancer correspondiente:

import { createStore, applyMiddleware, compose } from "redux";

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
    rootReducer,
    composeEnhancers(applyMiddleware(apiMiddleware, loggerMiddleware))
);

Conclusiones

El middleware en Redux es una herramienta poderosa para extender las capacidades de la biblioteca y manejar lógica compleja, como solicitudes asíncronas, registro de acciones y autorización. Crear middlewares personalizados te permite adaptar Redux a las necesidades específicas de tu aplicación, desde la integración con APIs hasta la implementación de flujos de depuración avanzados. Al seguir las mejores prácticas, como mantener la simplicidad y probar exhaustivamente, puedes construir middlewares robustos y eficientes que mejoren la escalabilidad de tus proyectos.

Con los ejemplos proporcionados, estás listo para implementar middlewares en tus aplicaciones Redux, ya sea con la biblioteca estándar o con Redux Toolkit. Experimenta con diferentes casos de uso y aprovecha herramientas como Redux DevTools para optimizar tu flujo de trabajo.