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

hot-wrapper.mddocs/

Hot Component Wrapper

The hot higher-order component (HOC) is the primary interface for enabling hot reloading on React components. It wraps components to preserve their state during hot module replacement while providing error boundaries and lifecycle management.

Capabilities

Hot Function

Creates a higher-order component that enables hot reloading for the wrapped component.

/**
 * Marks module and returns a HOC to mark a Component inside it as hot-exported
 * @param module - ALWAYS should be just "module"
 * @returns hot HOC function
 */
function hot(module: any): <T = React.ComponentType<any>>(Component: T, props?: AppContainerProps) => T;

interface AppContainerProps {
  errorBoundary?: boolean;
  errorReporter?: React.ComponentType<ErrorReporterProps>;
}

interface ErrorReporterProps {
  error: any;
}

Usage Examples:

// Basic usage with ES modules
import { hot } from 'react-hot-loader';

const MyComponent = () => <div>Hello World</div>;

export default hot(module)(MyComponent);
// Using root import (automatically detects module)
import { hot } from 'react-hot-loader/root';

const MyComponent = () => <div>Hello World</div>;

export default hot(MyComponent);
// TypeScript usage with props
import React from 'react';
import { hot } from 'react-hot-loader';

interface Props {
  name: string;
  age: number;
}

const UserProfile: React.FC<Props> = ({ name, age }) => (
  <div>
    <h1>{name}</h1>
    <p>Age: {age}</p>
  </div>
);

export default hot(module)(UserProfile);
// With custom error reporter
import { hot } from 'react-hot-loader';
import CustomErrorReporter from './CustomErrorReporter';

const MyApp = () => <div>My App</div>;

export default hot(module)(MyApp, {
  errorReporter: CustomErrorReporter,
  errorBoundary: true
});

Root Hot Function

Pre-configured version that automatically detects the calling module, eliminating the need to pass module parameter.

/**
 * Pre-configured hot function that automatically detects the calling module
 * @param Component - React component to make hot-reloadable
 * @param props - Optional AppContainer props
 * @returns Hot-wrapped component
 */
function hot<T = React.ComponentType<any>>(Component: T, props?: AppContainerProps): T;

Usage Examples:

import { hot } from 'react-hot-loader/root';

const App = () => {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  );
};

// No need to pass module
export default hot(App);

Hot Reload Behavior

State Preservation

  • Local component state: Preserved across hot reloads
  • Component props: Updated with new values from parent
  • Hooks state: Maintained with React's hook preservation
  • Context values: Updated if context provider changes

Module Integration

The hot wrapper integrates with module bundlers:

// Webpack HMR integration (automatic)
if (module.hot) {
  module.hot.accept('./MyComponent', () => {
    // Component will hot reload automatically
  });
}
// Parcel HMR integration (automatic)  
if (module.hot) {
  module.hot.accept(() => {
    // Hot reload handling
  });
}

Error Handling

Hot wrapped components automatically include error boundary functionality:

// Errors during hot reload are caught and displayed
const ProblematicComponent = () => {
  throw new Error('Development error');
  return <div>Won't render</div>;
};

export default hot(module)(ProblematicComponent);
// Error will be displayed in development, not crash the app

Advanced Usage

Custom Error Boundaries

import { hot } from 'react-hot-loader';

const MyErrorReporter = ({ error, errorInfo, component }) => (
  <div style={{ color: 'red', padding: '20px' }}>
    <h2>Development Error</h2>
    <details>
      <summary>Error Details</summary>
      <pre>{error.stack}</pre>
    </details>
    <button onClick={() => component.retryHotLoaderError()}>
      Retry
    </button>
  </div>
);

const App = () => <div>My App</div>;

export default hot(module)(App, {
  errorReporter: MyErrorReporter,
  errorBoundary: true
});

Production Behavior

In production builds, the hot wrapper becomes a no-op:

// Development: Full hot reload functionality
// Production: Returns component unchanged
export default hot(module)(MyComponent);

Limitations and Best Practices

Limitations

  • Only works in development mode with HMR enabled
  • Cannot preserve state of unmounted components
  • Some advanced React patterns may interfere with hot reloading
  • Class components with complex inheritance may have issues

Best Practices

// ✅ Good: Use at component export level
export default hot(module)(MyComponent);

// ❌ Avoid: Don't use inside render methods
const BadExample = () => {
  const HotComponent = hot(module)(SomeComponent); // Don't do this
  return <HotComponent />;
};

// ✅ Good: Use with functional components
const FunctionalComponent = () => <div>Hello</div>;
export default hot(module)(FunctionalComponent);

// ✅ Good: Use with class components  
class ClassComponent extends React.Component {
  render() { return <div>Hello</div>; }
}
export default hot(module)(ClassComponent);

// ✅ Good: One hot export per module
export default hot(module)(MainComponent);

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