Tweak React components in real time during development with Hot Module Replacement while preserving component state.
—
The AppContainer component is an error boundary that manages the hot reload lifecycle and provides error handling during development. It wraps React components to catch and display errors without crashing the entire application.
React component that serves as an error boundary and container for hot-reloadable components.
/**
* Error boundary component for hot reload management
* Catches errors during development and provides error recovery
*/
class AppContainer extends React.Component<AppContainerProps & AppChildren> {
constructor(props: AppContainerProps & AppChildren);
/** Catches errors during component rendering */
componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void;
/** Renders children with error boundary protection */
render(): React.ReactElement;
/** Retries after a hot loader error */
retryHotLoaderError(): void;
}
interface AppContainerProps {
/** Enable/disable error boundary functionality (default: true) */
errorBoundary?: boolean;
/** Custom error reporter component */
errorReporter?: React.ComponentType<ErrorReporterProps>;
}
interface AppChildren {
/** Single React element to wrap (validated) */
children?: React.ReactElement<any>;
}
interface ErrorReporterProps {
error: any;
errorInfo?: React.ErrorInfo;
component?: AppContainer;
}Usage Examples:
// Basic usage (legacy pattern)
import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import App from './App';
const render = (Component) => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.getElementById('root')
);
};
render(App);
// Enable hot reloading
if (module.hot) {
module.hot.accept('./App', () => {
render(App);
});
}// With custom error reporter
import { AppContainer } from 'react-hot-loader';
const CustomErrorDisplay = ({ error, errorInfo, component }) => (
<div className="error-boundary">
<h1>Development Error</h1>
<p>{error.message}</p>
<button onClick={() => component.retryHotLoaderError()}>
Try Again
</button>
</div>
);
const Root = () => (
<AppContainer
errorReporter={CustomErrorDisplay}
errorBoundary={true}
>
<App />
</AppContainer>
);// Disabled error boundary
import { AppContainer } from 'react-hot-loader';
const Root = () => (
<AppContainer errorBoundary={false}>
<App />
</AppContainer>
);AppContainer provides comprehensive error handling during development:
// Automatic error catching
const ProblematicComponent = () => {
// This error will be caught by AppContainer
throw new Error('Something went wrong!');
return <div>This won't render</div>;
};
const App = () => (
<AppContainer>
<ProblematicComponent />
</AppContainer>
);
// Error display instead of app crashBuilt-in error recovery mechanism for hot reload errors:
const ErrorReporter = ({ error, errorInfo, component }) => (
<div className="hot-reload-error">
<h2>Hot Reload Error</h2>
<details>
<summary>Error Details</summary>
<pre>{error.stack}</pre>
<pre>{JSON.stringify(errorInfo, null, 2)}</pre>
</details>
{/* Retry button triggers error recovery */}
<button onClick={() => component.retryHotLoaderError()}>
Retry Hot Reload
</button>
</div>
);AppContainer manages hot reload state internally:
// Internal state tracking (not directly accessible)
state = {
error: null,
errorInfo: null,
generation: 0 // Hot reload generation tracking
}// AppContainer integrates with React lifecycle
static getDerivedStateFromProps(nextProps, prevState) {
// Resets error state on hot reload
if (prevState.generation !== getGeneration()) {
return {
error: null,
generation: getGeneration(),
};
}
return null;
}
shouldComponentUpdate(prevProps, prevState) {
// Prevents infinite error loops
if (prevState.error && this.state.error) {
return false;
}
return true;
}In production builds, AppContainer becomes a simple pass-through component:
// Production AppContainer (simplified)
function AppContainer(props) {
return React.Children.only(props.children);
}import { AppContainer } from 'react-hot-loader';
// Full-featured error reporter
const AdvancedErrorReporter = ({ error, errorInfo, component }) => {
const [expanded, setExpanded] = React.useState(false);
return (
<div style={{
padding: '20px',
backgroundColor: '#ffe6e6',
border: '1px solid #ff9999'
}}>
<h2>🔥 Hot Reload Error</h2>
<p><strong>Error:</strong> {error.message}</p>
<button onClick={() => setExpanded(!expanded)}>
{expanded ? 'Hide' : 'Show'} Details
</button>
{expanded && (
<div>
<h3>Stack Trace:</h3>
<pre style={{ overflow: 'auto', maxHeight: '200px' }}>
{error.stack}
</pre>
<h3>Component Stack:</h3>
<pre style={{ overflow: 'auto', maxHeight: '200px' }}>
{errorInfo.componentStack}
</pre>
</div>
)}
<div style={{ marginTop: '10px' }}>
<button onClick={() => component.retryHotLoaderError()}>
🔄 Retry
</button>
<button onClick={() => window.location.reload()}>
🔃 Reload Page
</button>
</div>
</div>
);
};
// Usage with custom reporter
<AppContainer errorReporter={AdvancedErrorReporter}>
<App />
</AppContainer>AppContainer enforces single child requirement:
// ✅ Valid: Single child
<AppContainer>
<App />
</AppContainer>
// ❌ Invalid: Multiple children (throws error)
<AppContainer>
<Header />
<Main />
<Footer />
</AppContainer>
// ✅ Valid: Single wrapper element
<AppContainer>
<div>
<Header />
<Main />
<Footer />
</div>
</AppContainer>// ❌ Legacy pattern (still works)
import { AppContainer } from 'react-hot-loader';
const render = (Component) => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.getElementById('root')
);
};
// ✅ Modern pattern (recommended)
import { hot } from 'react-hot-loader/root';
const App = () => <div>My App</div>;
export default hot(App);
// AppContainer is included automatically// ✅ Good: Let AppContainer handle hot reload errors
<AppContainer errorBoundary={true}>
<App />
</AppContainer>
// ⚠️ Caution: Custom error boundaries might interfere
class MyErrorBoundary extends React.Component {
// Might catch errors that AppContainer should handle
}
// ✅ Better: Disable AppContainer error boundary if using custom
<AppContainer errorBoundary={false}>
<MyErrorBoundary>
<App />
</MyErrorBoundary>
</AppContainer>Install with Tessl CLI
npx tessl i tessl/npm-react-hot-loader