Registry /
testing / redux-immutable-state-invariant
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
muslnode 18–226 runs
build_error
glibcnode 18–226 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++
// });
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.
fixModify 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.
fixEnsure 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)`.
Audit
Dependencies
No dependency data recorded yet.