React Immutable Pure Component
This library provides `ImmutablePureComponent`, an enhanced React PureComponent specifically designed to work efficiently with Immutable.js data structures. It addresses the limitation of React's built-in `PureComponent` which doesn't fully leverage Immutable.js's structural sharing for shallow comparisons. The core mechanism involves `updateOnProps` and `updateOnStates` properties, allowing developers to explicitly define which specific props or state paths should trigger re-renders, using `Immutable.is` for deep equality checks on specified paths. The current stable version is 2.2.2. Releases have been somewhat sporadic, but updates address typings, dependency changes, and new features like `immutableMemo`. Its key differentiator is providing granular control over `Immutable.js`-aware re-rendering logic within a class component context, offering an alternative to `React.memo` with Immutable.js. It supports both class and functional components (via `immutableMemo`) and ships with TypeScript types.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'getIn')
cause Using `react-immutable-pure-component@2.0.1` with `Immutable.js` versions prior to `v4.0.0-rc`.fixUpgrade your `Immutable.js` dependency to `v4` or higher, or downgrade `react-immutable-pure-component` to `v1.x`. -
TypeError: path.map is not a function
cause Attempting to use non-string values (e.g., arrays for nested paths) in `updateOnProps` or `updateOnStates` with `Immutable.js` versions below 4.0.0.fixEnsure all elements in `updateOnProps` and `updateOnStates` arrays are `string` values for top-level keys. If you require nested path comparison, upgrade both `Immutable.js` to `v4+` and `react-immutable-pure-component` to `v2.0.1+`. -
Module not found: Can't resolve 'react-immutable-pure-component'
cause Incorrect import path or failure to resolve the module due to changes in packaging (from UMD to CJS/ESM).fixVerify your import statement (`import { ImmutablePureComponent } from 'react-immutable-pure-component';`) and ensure your bundler (Webpack, Rollup, etc.) is correctly configured to handle ES Modules or CommonJS. Check that the package is properly installed (`npm install react-immutable-pure-component`).
Warnings
- breaking Starting with v2.0.1, the package is no longer built as a UMD module. It is now distributed as standard CommonJS and ES6 modules. Direct browser script tag usage or older bundler configurations might break.
- breaking Version 2.0.1 temporarily increased the minimal required `Immutable.js` version to `>= 4` due to its internal use of `getIn`. If you were using `Immutable.js` versions below 4 with `react-immutable-pure-component@1`, upgrading directly to 2.0.1 would cause issues.
- gotcha With `react-immutable-pure-component@2.1.0` onwards, the restriction of `Immutable.js v4+` was relaxed for basic usage. If `updateOnProps` and `updateOnStates` only contain `string` values (representing top-level keys), `Immutable.js` versions below 4 will work. However, using non-string values (e.g., path arrays for nested access) with `Immutable.js < 4` will result in a `TypeError`.
- gotcha The `updateOnProps` and `updateOnStates` properties expect an array of strings representing the keys to check for changes, or `undefined` to check all keys. Passing a non-array or non-string value (for individual elements in the array) for `Immutable.js` versions below 4 when using complex paths will cause runtime errors.
- gotcha Prior to v2.2.0, the library internally used `Immutable.js`'s `getIn` method, which had a known issue (immutable-js/immutable-js#1688) related to `path` functionality. This could lead to unexpected behavior or incorrect comparisons for deeply nested paths.
Install
-
npm install react-immutable-pure-component -
yarn add react-immutable-pure-component -
pnpm add react-immutable-pure-component
Imports
- ImmutablePureComponent
const ImmutablePureComponent = require('react-immutable-pure-component').ImmutablePureComponent;import { ImmutablePureComponent } from 'react-immutable-pure-component'; - immutableMemo
import immutableMemo from 'react-immutable-pure-component';
import { immutableMemo } from 'react-immutable-pure-component'; - Default Export (ImmutablePureComponent)
const ImmutablePureComponent = require('react-immutable-pure-component');import ImmutablePureComponent from 'react-immutable-pure-component';
Quickstart
import React, { useState, useCallback } from 'react';
import { ImmutablePureComponent, immutableMemo } from 'react-immutable-pure-component';
import { Map, List } from 'immutable';
// A class component using ImmutablePureComponent
class MyClassComponent extends ImmutablePureComponent<{ data: Map<string, any>, label: string }, { count: number }> {
// Specify props to check for updates using Immutable.is
updateOnProps = ['data'];
// Specify state keys to check for updates
updateOnStates = ['count'];
constructor(props: any) {
super(props);
this.state = { count: 0 };
}
componentDidMount() {
// Example: Update internal state after some time
setTimeout(() => {
this.setState({ count: 1 });
}, 1000);
}
render() {
console.log(`MyClassComponent (${this.props.label}) rendered`);
return (
<div>
<h3>Class Component: {this.props.label}</h3>
<p>Data Version: {this.props.data.get('version')}</p>
<p>Internal Count: {this.state.count}</p>
</div>
);
}
}
// A functional component using immutableMemo
interface MyFuncProps {
items: List<string>;
onClick: (item: string) => void;
}
const MyFunctionalComponent = immutableMemo<MyFuncProps>(({ items, onClick }) => {
console.log('MyFunctionalComponent rendered');
return (
<div>
<h3>Functional Component</h3>
<ul>
{items.map((item, index) => (
<li key={index} onClick={() => onClick(item)}>{item}</li>
))}
</ul>
</div>
);
}, ['items']); // 'items' array specifies props to compare with Immutable.is
const App = () => {
const [data, setData] = useState(Map({ version: 1 }));
const [items, setItems] = useState(List(['Apple', 'Banana']));
const updateData = () => {
// Only updates if the new Map is structurally different on specified keys
setData(data => data.set('version', data.get('version') + 1));
};
const handleItemClick = useCallback((item: string) => {
console.log(`Clicked: ${item}`);
}, []);
return (
<div>
<h1>React Immutable Pure Component Demo</h1>
<button onClick={updateData}>Update Data Version</button>
<MyClassComponent data={data} label="Example 1" />
{/* This component will only re-render if 'data' specifically changes (version increments) */}
<MyFunctionalComponent items={items} onClick={handleItemClick} />
{/* This component will only re-render if 'items' List changes structurally */}
</div>
);
};
export default App;