Redux Pack Middleware for Promise Handling

raw JSON →
0.1.5 verified Thu Apr 23 auth: no javascript abandoned

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.

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.
cause The `redux-pack` middleware has not been applied to the Redux store, or it's misconfigured, causing Redux to treat the promise-returning action as a non-plain object.
fix
Ensure 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
cause The `handle` utility from `redux-pack` was not imported correctly or `redux-pack` itself was not installed.
fix
Verify that 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).
cause An action dispatched using `redux-pack`'s expected format (an object with a `promise` key) either did not contain a `promise` key or the value associated with `promise` was not a valid Promise instance.
fix
Ensure your action creator returns an object with a promise key whose value is an actual Promise: return { type: 'MY_ACTION', promise: myAsyncFunction(), ... };
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).
fix Avoid using `redux-pack` for new projects. For existing projects, consider migrating to Redux Toolkit's `createAsyncThunk` for modern async logic handling, which is actively maintained and officially supported by the Redux team.
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.
fix Ensure your build tool is configured to correctly handle CJS modules, or preferably, migrate to a modern solution like Redux Toolkit which offers full ESM/CJS compatibility.
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.
fix Familiarize yourself with Redux Toolkit and its `createAsyncThunk` for managing async operations. It is the recommended and best-practice approach in the current Redux ecosystem.
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).
fix If using `redux-pack` in a TypeScript project, ensure you install `@types/redux-pack`. However, for robust type safety and modern TypeScript features, migration to Redux Toolkit is strongly recommended.
npm install redux-pack
yarn add redux-pack
pnpm add redux-pack

Demonstrates setting up a Redux store with `redux-pack` middleware, defining a promise-based action, and handling its lifecycle in a reducer using the `handle` utility, including optional lifecycle hooks in `meta`.

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);