Registry / testing / redux-immutable-state-invariant

redux-immutable-state-invariant

JSON →
library2.1.0jsnpmunverified

Redux-immutable-state-invariant is a specialized Redux middleware designed exclusively for development environments. Its core function is to detect unintended mutations of the Redux state, both within a reducer's dispatch cycle and between dispatches. This is crucial for upholding the immutability principle central to Redux, preventing subtle bugs that arise from direct state modification rather than returning new state objects. The current stable version is 2.1.0, with a release cadence that has seen significant updates around v1 and v2, and more recently a minor bug fix in v2.1.0, indicating ongoing maintenance. Unlike libraries like Immutable.js which provide immutable data structures, this middleware acts as a runtime check for native JavaScript objects and arrays, throwing descriptive errors when mutations are detected. It is explicitly warned against using in production due to its performance overhead caused by extensive object copying for comparison.

npm install redux-immutable-state-invariant
INSTALL
IMPORT
SIG · REDUX-IMMUTABLE-ST
R
redux-immutable-state-invariant
testingjavascriptv2.1.0
Install
Import
Disk
Pass rate
0/ 6
Env Coverage0 / 6
glibc
1822
musl
1822
Install & Compatibility
Where this runs
tested against v? · npm install
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
node 18226 runs
build_error
glibc
node 18226 runs
build_error
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

immutableStateInvariantMiddleware
import immutableStateInvariantMiddleware from 'redux-immutable-state-invariant';
import { immutableStateInvariantMiddleware } from 'redux-immutable-state-invariant';
The primary export is a default export, which is a factory function to create the middleware.
createImmutableStateInvariantMiddleware
const createImmutableStateInvariantMiddleware = require('redux-immutable-state-invariant').default;
const createImmutableStateInvariantMiddleware = require('redux-immutable-state-invariant');
Since v2.0.0, CommonJS `require` must access the `.default` property due to Babel 6 transpilation. The module exports a factory function, conventionally named like `create...`.
MiddlewareFactoryWithOptions
immutableStateInvariantMiddleware({ isImmutable: (val) => typeof val !== 'object', ignore: ['users.drafts'] });
immutableStateInvariantMiddleware((val) => typeof val !== 'object');
Since v2.0.0, the middleware factory accepts a single `options` object with properties like `isImmutable` and `ignore`.

This example demonstrates how to integrate `redux-immutable-state-invariant` into a Redux store, showing both correct immutable updates and how the middleware catches direct state mutations in reducers. It also illustrates how to configure the middleware with `ignore` paths and a custom `isImmutable` function, while emphasizing its development-only usage.

import { applyMiddleware, combineReducers, createStore } from 'redux'; import thunk from 'redux-thunk'; import immutableStateInvariantMiddleware from 'redux-immutable-state-invariant'; const initialState = { counter: 0, user: { name: 'Alice', age: 30, address: { street: 'Main St' } } }; function counterReducer(state = initialState.counter, action) { switch (action.type) { case 'INCREMENT': return state + 1; case 'DECREMENT': // BAD: Mutates state directly, will be caught by middleware // state--; return state - 1; default: return state; } } function userReducer(state = initialState.user, action) { switch (action.type) { case 'SET_USERNAME': // BAD: Mutates state directly, will be caught by middleware // state.name = action.payload; // GOOD: Returns new state object return { ...state, name: action.payload }; case 'SET_ADDRESS_STREET': // BAD: Deep mutation, will be caught // state.address.street = action.payload; // GOOD: Returns new nested state objects return { ...state, address: { ...state.address, street: action.payload } }; default: return state; } } const rootReducer = combineReducers({ counter: counterReducer, user: userReducer }); // Configure middleware to ignore specific paths or custom immutability checks const middlewareConfig = { ignore: ['user.address.zipCode'], // Example: ignore a specific path isImmutable: (value) => { // Custom check: treat anything with a '__immutable' property as immutable if (typeof value === 'object' && value !== null && value.__immutable) { return true; } // Default check for primitives return typeof value !== 'object' || value === null; } }; const middleware = process.env.NODE_ENV !== 'production' ? [immutableStateInvariantMiddleware(middlewareConfig), thunk] : [thunk]; const store = createStore( rootReducer, applyMiddleware(...middleware) ); console.log('Initial state:', store.getState()); store.dispatch({ type: 'INCREMENT' }); console.log('State after INCREMENT:', store.getState()); store.dispatch({ type: 'SET_USERNAME', payload: 'Bob' }); console.log('State after SET_USERNAME:', store.getState()); // Intentionally trigger a mutation (uncomment to see the error in development) // store.dispatch({ // type: 'MUTATE_COUNTER_BADLY', // payload: store.getState().counter++ // });
Debug
Known issues
breakingFor CommonJS environments, `require('redux-immutable-state-invariant')` no longer directly returns the middleware factory. You must now access the `.default` property.
fix
Change `const createMiddleware = require('redux-immutable-state-invariant');` to `const createMiddleware = require('redux-immutable-state-invariant').default;`.
affects: >=2.0.0
breakingThe middleware factory function (the default export) now accepts a single `options` object as its argument, rather than direct arguments like `isImmutable`.
fix
If you were passing `isImmutable` directly, wrap it in an object: `immutableStateInvariantMiddleware(myIsImmutableFn)` becomes `immutableStateInvariantMiddleware({ isImmutable: myIsImmutableFn })`. The `options` object also supports an `ignore` property for paths.
affects: >=2.0.0
gotchaThis middleware is strictly for development environments. Using it in production will severely degrade application performance due to extensive deep copying and comparison of state objects required for mutation detection.
fix
Always conditionally apply this middleware based on `process.env.NODE_ENV` or similar environment variables, ensuring it is only included when `NODE_ENV !== 'production'`.
affects: >=1.0.0
Errors
Common errors & fixes
TypeError: (0 , _reduxImmutableStateInvariant2.default) is not a function
Attempting to use `require('redux-immutable-state-invariant')` in a CommonJS environment without accessing the `.default` property for versions 2.0.0 and above.
fix
Modify your `require` statement to `const createImmutableStateInvariantMiddleware = require('redux-immutable-state-invariant').default;`.
Uncaught Error: A state mutation was detected between dispatches. Previous state was { ... }, Next state is { ... }
Directly modifying a Redux state object or array property in a reducer or an asynchronous action after the initial state snapshot, rather than returning a new, modified copy.
fix
Ensure all Redux reducers and async logic that modifies state adhere to immutability. Use spread syntax (`...`) for objects and arrays, or immutable helper libraries, to create new instances of state for any changes. Avoid direct assignments like `state.property = value` or `state.array.push(item)`.
Upgrade
Version history
2.1.0latest on npm
Audit
Dependencies

No dependency data recorded yet.

Agent activity
12 hits · last 30 days
node
12
Resources
redux-immutable-state-invariant — npm install redux-immutable-state-invariant · libregistry