Fastest deep equal comparison for React with optimizations for React elements and circular reference handling
npx @tessl/cli install tessl/npm-react-fast-compare@3.2.0React Fast Compare provides the fastest deep equal comparison for React applications, with optimizations for React elements and built-in circular reference handling. It offers a single unified entry point that handles React-specific circular references like React elements, includes try/catch guardrails for stack overflows, and supports all JavaScript data types.
npm install react-fast-compare or yarn add react-fast-compareconst isEqual = require('react-fast-compare');For ES modules/TypeScript:
import isEqual = require('react-fast-compare');const isEqual = require('react-fast-compare');
// General deep comparison
console.log(isEqual({ foo: 'bar' }, { foo: 'bar' })); // true
console.log(isEqual([1, 2, 3], [1, 2, 3])); // true
// React.memo usage
const MemoComponent = React.memo(ExpensiveComponent, isEqual);
// shouldComponentUpdate usage
class Component extends React.Component {
shouldComponentUpdate(nextProps) {
return !isEqual(this.props, nextProps);
}
}
// React-Redux useSelector usage
const value = useSelector(selector, isEqual);Performs deep equality comparison optimized for React applications with circular reference handling.
/**
* Compare two values for deep equality with React-specific optimizations
* @param a - First value to compare
* @param b - Second value to compare
* @returns true if values are deeply equal, false otherwise
*/
function isEqual<A = any, B = any>(a: A, b: B): boolean;Supported Data Types:
React-Specific Features:
_owner, __v, __o properties in React/Preact elements to avoid infinite loopsError Handling:
false and logs "react-fast-compare cannot handle circular refs" warningfalsePerformance Characteristics:
Usage Examples:
// Basic object comparison
isEqual({ name: 'Alice', age: 25 }, { name: 'Alice', age: 25 }); // true
isEqual({ name: 'Alice' }, { name: 'Bob' }); // false
// Array comparison
isEqual([1, 2, [3, 4]], [1, 2, [3, 4]]); // true
isEqual([1, 2, 3], [1, 2, 4]); // false
// Date comparison
isEqual(new Date('2023-01-01'), new Date('2023-01-01')); // true
isEqual(new Date('2023-01-01'), new Date('2023-01-02')); // false
// RegExp comparison
isEqual(/abc/gi, /abc/gi); // true
isEqual(/abc/g, /abc/i); // false
// Map comparison
const map1 = new Map([['a', 1], ['b', 2]]);
const map2 = new Map([['a', 1], ['b', 2]]);
isEqual(map1, map2); // true
// Set comparison
const set1 = new Set([1, 2, 3]);
const set2 = new Set([1, 2, 3]);
isEqual(set1, set2); // true
// React element comparison (skips circular references)
const element1 = React.createElement('div', { id: 'test' }, 'Hello');
const element2 = React.createElement('div', { id: 'test' }, 'Hello');
isEqual(element1, element2); // true (ignores _owner and other circular props)
// Typed array comparison
const arr1 = new Uint8Array([1, 2, 3]);
const arr2 = new Uint8Array([1, 2, 3]);
isEqual(arr1, arr2); // trueIntegration Examples:
// React.memo with custom comparison
interface Props {
data: ComplexObject;
config: ConfigObject;
}
const OptimizedComponent = React.memo<Props>(({ data, config }) => {
// Expensive component logic
return <div>{/* Complex UI */}</div>;
}, isEqual);
// Class component shouldComponentUpdate
class ExpensiveList extends React.Component<ListProps> {
shouldComponentUpdate(nextProps: ListProps) {
// Only re-render if props actually changed
return !isEqual(this.props, nextProps);
}
render() {
return (
<ul>
{this.props.items.map(item =>
<li key={item.id}>{item.name}</li>
)}
</ul>
);
}
}
// React-Redux useSelector with equality check
const selectUserData = (state: RootState) => ({
user: state.user,
preferences: state.preferences,
settings: state.settings
});
function UserProfile() {
// Prevents unnecessary re-renders when reference changes but content is same
const userData = useSelector(selectUserData, isEqual);
return <div>{userData.user.name}</div>;
}