Tweak React components in real time during development with Hot Module Replacement while preserving component state.
—
React Hot Loader provides utility functions for component comparison, cold component marking, and hot reload control. These utilities help manage component hot reloading behavior and provide fine-grained control over the hot reload process.
Tests whether two React component types are equal, taking into account proxy components used by hot reloading.
/**
* Tests if types of two components are equal
* @param typeA - First component type
* @param typeB - Second component type
* @returns true if components are equal (considering hot reload proxies)
*/
function areComponentsEqual<T>(typeA: React.ComponentType<T>, typeB: React.ComponentType<T>): boolean;Usage Examples:
import { areComponentsEqual } from 'react-hot-loader';
const ComponentA = () => <div>A</div>;
const ComponentB = () => <div>B</div>;
// Basic comparison
console.log(areComponentsEqual(ComponentA, ComponentA)); // true
console.log(areComponentsEqual(ComponentA, ComponentB)); // false
// Hot reload scenario
const OriginalComponent = () => <div>Original</div>;
// After hot reload, component reference changes but areComponentsEqual
// will return true if it's the same logical component
const hotReloadedComponent = () => <div>Updated</div>;
// This accounts for hot reload proxies
console.log(areComponentsEqual(OriginalComponent, hotReloadedComponent));
// May return true if they're the same component after hot reload// TypeScript usage with generic types
interface Props {
name: string;
}
const UserComponent: React.FC<Props> = ({ name }) => <div>{name}</div>;
const AdminComponent: React.FC<Props> = ({ name }) => <div>Admin: {name}</div>;
const isSameComponent = areComponentsEqual(UserComponent, AdminComponent);
console.log(isSameComponent); // false// Testing in component lifecycle
class MyComponent extends React.Component {
shouldComponentUpdate(nextProps) {
// Check if the component type has changed due to hot reload
return !areComponentsEqual(this.constructor, nextProps.componentType);
}
render() {
return <div>My Component</div>;
}
}Marks a component as "cold", making it invisible to React Hot Loader. Changes to cold components will cause local state loss and full re-mounting.
/**
* Marks component as cold, making it invisible for React-Hot-Loader
* Any changes to that component will cause local state loss
* @param component - Component to mark as cold
* @returns The same component (unchanged)
*/
function cold<T = React.ComponentType<any>>(component: T): T;Usage Examples:
import React from 'react';
import { cold } from 'react-hot-loader';
// Mark a component as cold
const StaticComponent = cold(() => {
return <div>This component won't hot reload</div>;
});
export default StaticComponent;
// Changes to this component will cause full re-mount, losing state// Cold class component
import { cold } from 'react-hot-loader';
class DatabaseConnection extends React.Component {
constructor(props) {
super(props);
this.connection = establishConnection();
}
componentWillUnmount() {
this.connection.close();
}
render() {
return <div>Connected to database</div>;
}
}
// Mark as cold to prevent hot reload interference with database connection
export default cold(DatabaseConnection);// TypeScript cold component
import { cold } from 'react-hot-loader';
interface CriticalProps {
securityToken: string;
}
const SecurityComponent: React.FC<CriticalProps> = ({ securityToken }) => {
// This component handles sensitive operations
return <div>Secure Area</div>;
};
// Mark as cold for security reasons - always full reload
export default cold(SecurityComponent);// Conditional cold marking
import { cold } from 'react-hot-loader';
const MyComponent = () => <div>My Component</div>;
// Only mark as cold in certain conditions
const shouldBeCold = process.env.DISABLE_HOT_RELOAD === 'true';
const ExportedComponent = shouldBeCold ? cold(MyComponent) : MyComponent;
export default ExportedComponent;import { hot, cold } from 'react-hot-loader';
// Hot reload for UI components
const UIComponent = hot(module)(() => <div>UI Component</div>);
// Cold for critical system components
const SystemComponent = cold(() => <div>System Component</div>);
// Mixed usage in app
const App = () => (
<div>
<UIComponent /> {/* Will hot reload and preserve state */}
<SystemComponent /> {/* Will full reload and reset state */}
</div>
);
export default hot(module)(App);import { areComponentsEqual } from 'react-hot-loader';
import { render } from '@testing-library/react';
describe('Component equality', () => {
it('should recognize same components', () => {
const ComponentA = () => <div>Test</div>;
const ComponentB = () => <div>Test</div>;
// In testing, these are different functions
expect(areComponentsEqual(ComponentA, ComponentA)).toBe(true);
expect(areComponentsEqual(ComponentA, ComponentB)).toBe(false);
});
it('should handle hot reloaded components', () => {
// Mock hot reload scenario
const originalComponent = () => <div>Original</div>;
// Simulate hot reload by creating new component with same "identity"
const reloadedComponent = () => <div>Reloaded</div>;
// In actual hot reload, these would be considered equal
// Test your specific hot reload logic here
});
});import React from 'react';
import { cold } from 'react-hot-loader';
// Error boundary should be cold to prevent hot reload issues
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
console.error('Error caught by boundary:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return <div>Something went wrong.</div>;
}
return this.props.children;
}
}
// Mark error boundary as cold for reliability
export default cold(ErrorBoundary);import { cold } from 'react-hot-loader';
import SomeThirdPartyComponent from 'some-library';
// Third-party components often don't work well with hot reload
const SafeThirdPartyComponent = cold(SomeThirdPartyComponent);
// Wrapper component can still be hot
const MyWrapper = ({ data }) => (
<div>
<h1>My App</h1>
<SafeThirdPartyComponent data={data} />
</div>
);
export default hot(module)(MyWrapper);// ✅ Good candidates for cold():
// - Components with complex initialization
// - Components that manage external resources
// - Third-party components
// - Error boundaries
// - Components with side effects in constructor
// ❌ Avoid cold() for:
// - Simple presentational components
// - Components you frequently modify
// - Components where state preservation is important// areComponentsEqual() is lightweight but consider caching for heavy usage
const componentComparison = useMemo(() => {
return areComponentsEqual(ComponentA, ComponentB);
}, [ComponentA, ComponentB]);import { areComponentsEqual, cold } from 'react-hot-loader';
const DebugComponent = ({ children }) => {
useEffect(() => {
// Debug component equality issues
console.log('Component equality check:',
areComponentsEqual(children.type, children.type)
);
}, [children]);
return children;
};
// Use cold for debugging to avoid hot reload interference
export default cold(DebugComponent);// Old way (manual proxy checking)
const getActualComponent = (component) => {
return component.__hotReloadProxy ?
component.__hotReloadProxy.getCurrent() :
component;
};
const manualComparison = (a, b) => {
return getActualComponent(a) === getActualComponent(b);
};
// New way (recommended)
import { areComponentsEqual } from 'react-hot-loader';
const modernComparison = areComponentsEqual(a, b);Sets specific options for individual components, providing fine-grained control over hot reload behavior for specific components.
/**
* Configure options for a specific component
* @param component - Component to configure
* @param options - Configuration options for the component
* @returns Configured component
*/
function configureComponent(component: React.ComponentType<any>, options: any): React.ComponentType<any>;Usage Examples:
import { configureComponent } from 'react-hot-loader';
const MyComponent = () => <div>My Component</div>;
// Configure component with specific options
const ConfiguredComponent = configureComponent(MyComponent, {
pureSFC: true,
pureRender: false
});
export default ConfiguredComponent;// Configure multiple components differently
const FastComponent = configureComponent(ComponentA, {
pureSFC: true,
pureRender: true
});
const RichComponent = configureComponent(ComponentB, {
pureSFC: false,
allowSFC: true
});// ✅ Good: Export cold components directly
export default cold(MyComponent);
// ✅ Good: Conditional cold based on environment
export default process.env.NODE_ENV === 'test'
? cold(MyComponent)
: hot(module)(MyComponent);
// ❌ Avoid: Mixing hot and cold on same component
const Component = hot(module)(cold(MyComponent)); // Don't do this
// ❌ Avoid: Cold inside render methods
const BadExample = () => {
const ColdComponent = cold(SomeComponent); // Don't do this
return <ColdComponent />;
};Install with Tessl CLI
npx tessl i tessl/npm-react-hot-loader