Redux Logic Middleware
raw JSON →Redux Logic is a middleware for Redux applications designed to centralize and organize business logic and side effects. It allows developers to intercept actions and perform asynchronous processing, supporting various JavaScript styles including callbacks, Promises, async/await, and Observables (via RxJS). The current stable version is 5.0.2. Release cadence typically involves minor and patch versions for dependency updates and security fixes, with major versions reserved for significant changes like dropping Node.js version support or altering internal event structures. Key differentiators include its declarative API for common side effect patterns (filtering, cancellation, latest request handling, debouncing, throttling), robust testing support via `redux-logic-test`, simplified server-side rendering, and the ability to dynamically load logic for code-splitting scenarios. It aims to provide a flexible alternative to libraries like Redux Saga and Redux Observable by allowing developers to choose their preferred async programming paradigm within a declarative framework.
Common errors
error Error: Cannot find module 'redux' ↓
redux in your project: npm install redux or yarn add redux. error TypeError: (0 , redux_logic_1.createLogic) is not a function ↓
import { createLogic } from 'redux-logic'; for ESM, or const { createLogic } = require('redux-logic'); for CJS) and that your bundler/TypeScript configuration is set up correctly for module resolution. error TypeError: middleware is not a function (when applying middleware) ↓
createLogicMiddleware with your logic array, like applyMiddleware(createLogicMiddleware([myLogic])), rather than applyMiddleware(createLogicMiddleware). error TypeError: Cannot read properties of undefined (reading 'message') in monitor$ handler ↓
monitor$ handler to properly check if err is an Error object before accessing its properties, e.g., error.message or error.stack. Warnings
breaking The `monitor$` notification event handler now signals with the raw error object (`err`) instead of just the error message (`err.message`) if an error was thrown. Code expecting a string should be updated to handle an `Error` object. ↓
breaking Node.js v6 support was dropped in `redux-logic` v3.0.0 due to dependency upgrades. Applications running on Node.js v6 or older will encounter compatibility issues. ↓
gotcha The UMD build of `redux-logic` is no longer ES5 compatible as of v5.0.0; it now targets ES6. If you are using the UMD build directly in browsers that only support ES5, it will likely break. ↓
gotcha A 'slight reduction in the number of logics that can be loaded' was noted in v5.0.0 due to updates in the RxJS library. While not an API change, extremely large applications might theoretically hit new internal limits. ↓
Install
npm install redux-logic yarn add redux-logic pnpm add redux-logic Imports
- createLogic wrong
const createLogic = require('redux-logic').createLogic;correctimport { createLogic } from 'redux-logic'; - createLogicMiddleware wrong
const createLogicMiddleware = require('redux-logic').createLogicMiddleware;correctimport { createLogicMiddleware } from 'redux-logic'; - Logic
import type { Logic } from 'redux-logic';
Quickstart
import { createStore, applyMiddleware } from 'redux';
import { createLogic, createLogicMiddleware } from 'redux-logic';
import axios from 'axios'; // Example dependency, install if needed: npm install axios
const FETCH_POLLS = 'FETCH_POLLS';
const FETCH_POLLS_SUCCESS = 'FETCH_POLLS_SUCCESS';
const FETCH_POLLS_FAILED = 'FETCH_POLLS_FAILED';
const CANCEL_FETCH_POLLS = 'CANCEL_FETCH_POLLS';
// Reducer
const initialState = { polls: [], loading: false, error: null };
function reducer(state = initialState, action) {
switch (action.type) {
case FETCH_POLLS: return { ...state, loading: true, error: null };
case FETCH_POLLS_SUCCESS: return { ...state, loading: false, polls: action.payload };
case FETCH_POLLS_FAILED: return { ...state, loading: false, error: action.payload };
default: return state;
}
}
// Logic definition
const fetchPollsLogic = createLogic({
type: FETCH_POLLS,
cancelType: CANCEL_FETCH_POLLS,
latest: true,
process({ getState, action }, dispatch, done) {
axios
.get('https://survey.codewinds.com/polls')
.then((resp) => resp.data.polls)
.then((polls) => dispatch({ type: FETCH_POLLS_SUCCESS, payload: polls }))
.catch((err) => {
console.error('Fetch polls error:', err); // Log error
dispatch({ type: FETCH_POLLS_FAILED, payload: err.message, error: true });
})
.then(() => done()); // Always call done when finished
}
});
// Configure middleware and store
const logicMiddleware = createLogicMiddleware([fetchPollsLogic]);
const store = createStore(reducer, applyMiddleware(logicMiddleware));
// Dispatch an action to trigger the logic
console.log('Dispatching FETCH_POLLS action...');
store.dispatch({ type: FETCH_POLLS });
// Optional: Simulate cancellation after a delay
// setTimeout(() => {
// console.log('Dispatching CANCEL_FETCH_POLLS action...');
// store.dispatch({ type: CANCEL_FETCH_POLLS });
// }, 100);
// Listen for state changes (for demonstration)
const unsubscribe = store.subscribe(() => {
console.log('Current state:', store.getState());
if (!store.getState().loading) {
unsubscribe(); // Stop listening once loading is complete
}
});