CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-hot-loader

Tweak React components in real time during development with Hot Module Replacement while preserving component state.

Pending
Overview
Eval results
Files

app-container.mddocs/

App Container

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.

Capabilities

AppContainer Component

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>
);

Error Handling

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 crash

Error Recovery

Built-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>
);

Hot Reload Integration

State Management

AppContainer manages hot reload state internally:

// Internal state tracking (not directly accessible)
state = {
  error: null,
  errorInfo: null,
  generation: 0  // Hot reload generation tracking
}

Lifecycle Integration

// 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;
}

Production Behavior

In production builds, AppContainer becomes a simple pass-through component:

// Production AppContainer (simplified)
function AppContainer(props) {
  return React.Children.only(props.children);
}

Advanced Usage

Custom Error Reporters

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>

Multiple Children Validation

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>

Migration Notes

Modern vs Legacy Usage

// ❌ 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

Error Boundary Best Practices

// ✅ 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

docs

app-container.md

build-integration.md

component-utilities.md

configuration.md

hot-wrapper.md

index.md

tile.json