Redux Pack Middleware for Promise Handling
raw JSON →Redux Pack is a Redux middleware library designed to simplify the handling of asynchronous actions through a declarative, promise-based approach. It aims to reduce boilerplate and prevent common issues associated with `redux-thunk`, such as multiple sequential dispatches causing performance penalties and inconsistent state, by treating a promise's lifecycle as a single action. The library's core utility is the `handle` function, which allows reducers to declaratively respond to the start, success, failure, and completion of a promise. However, the package, currently at version 0.1.5, was last published in March 2017. It is considered abandoned, lacks support for modern Redux versions (e.g., v5+), contemporary JavaScript features like ES Modules, and is superseded by Redux Toolkit's `createAsyncThunk` for robust and officially recommended async logic management. Community-maintained TypeScript types (`@types/redux-pack`) exist, but the core library itself does not offer official type support.
Common errors
error Error: Actions must be plain objects. Instead, the actual type was: 'Promise'. You may need to add middleware to your store setup to handle dispatching other values, such as 'redux-thunk' to handle dispatching functions. ↓
reduxPackMiddleware is correctly applied to your Redux store using applyMiddleware: const store = createStore(rootReducer, applyMiddleware(reduxPackMiddleware)); error TypeError: Cannot read properties of undefined (reading 'handle') or handle is not a function ↓
redux-pack is installed (npm install redux-pack or yarn add redux-pack) and that handle is imported as a named export: import { handle } from 'redux-pack'; error TypeError: A promise must be returned from the action creator (or present in the `promise` key of the action object). ↓
promise key whose value is an actual Promise: return { type: 'MY_ACTION', promise: myAsyncFunction(), ... }; Warnings
breaking Redux Pack is effectively abandoned, with its last npm package update (v0.1.5) occurring in March 2017. This means it is highly unlikely to receive updates for security vulnerabilities, bug fixes, or compatibility with newer versions of Redux, React, or JavaScript features (like ES Modules). ↓
gotcha This library was designed before modern ES Modules (ESM) were standard in the JavaScript ecosystem. It ships with CommonJS (CJS) modules and may have compatibility issues or require specific bundler configurations (e.g., Webpack, Rollup, Vite) to work correctly in an ESM-first environment. ↓
gotcha Redux Pack's approach to promise handling has been largely superseded by Redux Toolkit, specifically the `createAsyncThunk` utility. Redux Toolkit provides a more integrated, opinionated, and modern solution for async logic, including built-in handling of loading states, errors, and TypeScript support, which `redux-pack` predates. ↓
gotcha The `redux-pack` library itself does not ship with official TypeScript type definitions. While community-contributed types (`@types/redux-pack`) exist and are actively maintained by the DefinitelyTyped project, relying solely on community types can sometimes lead to inconsistencies or delays in supporting new library features (though this is less relevant for an abandoned library). ↓
Install
npm install redux-pack yarn add redux-pack pnpm add redux-pack Imports
- reduxPackMiddleware wrong
import reduxPackMiddleware from 'redux-pack'; // CommonJS style for older default exports or incorrect named import const reduxPackMiddleware = require('redux-pack'); // Not designed for direct require() in modern setupscorrectimport { middleware as reduxPackMiddleware } from 'redux-pack'; - handle wrong
const handle = require('redux-pack').handle; // Old CommonJS syntax import handle from 'redux-pack'; // Incorrect if it's a named exportcorrectimport { handle } from 'redux-pack'; - ACTION_TYPE_NAME wrong
import { LOAD_FOO } from 'redux-pack'; // Action types are user-defined, not imported from the library.correctexport const LOAD_FOO = 'LOAD_FOO';
Quickstart
import { createStore, applyMiddleware, combineReducers } from 'redux';
import { middleware as reduxPackMiddleware, handle } from 'redux-pack';
// 1. Define Action Types
export const LOAD_USER = 'LOAD_USER';
// 2. Define an API utility (mock for example)
const Api = {
getUser: (id) => new Promise(resolve => {
setTimeout(() => {
console.log(`Fetching user ${id}...`);
resolve({ id, name: `User ${id}`, email: `user${id}@example.com` });
}, 500);
})
};
// 3. Create an Action Creator
export function loadUser(id) {
return {
type: LOAD_USER,
promise: Api.getUser(id),
meta: {
onStart: () => console.log(`Starting fetch for user ${id}`),
onSuccess: (payload) => console.log('User fetched successfully:', payload),
onFailure: (error) => console.error('Failed to fetch user:', error),
// Other hooks: onFinish, always
}
};
}
// 4. Create a Reducer
const initialState = {
user: null,
isLoading: false,
error: null
};
function userReducer(state = initialState, action) {
switch (action.type) {
case LOAD_USER:
return handle(state, action, {
start: prevState => ({ ...prevState, isLoading: true, error: null }),
success: prevState => ({ ...prevState, isLoading: false, user: action.payload }),
failure: prevState => ({ ...prevState, isLoading: false, error: action.payload }),
finish: prevState => ({ ...prevState })
});
default:
return state;
}
}
// 5. Configure the Redux Store
const rootReducer = combineReducers({
user: userReducer
});
const store = createStore(
rootReducer,
applyMiddleware(reduxPackMiddleware)
);
// 6. Dispatch the action
console.log('Initial state:', store.getState());
store.dispatch(loadUser(123));
store.subscribe(() => {
console.log('Current state:', store.getState());
});
// Example dispatch for a second user (showing different state change)
setTimeout(() => {
store.dispatch(loadUser(456));
}, 1500);