Frontend Development 21 min read

The Evolution and Implementation of React Hot Loader

An in‑depth exploration of React Hot Loader’s origins, underlying HMR principles, challenges with state and DOM preservation, the development of proxy‑based solutions, React Transform, and the progression to newer versions, providing practical code examples and insights for frontend developers.

Hujiang Technology
Hujiang Technology
Hujiang Technology
The Evolution and Implementation of React Hot Loader

If you use React, you will often encounter Dan Abramov’s contributions such as React Hot Loader, React Transform, redux‑thunk, and redux‑devtools. Dan joined Facebook in 2015 and describes his goal as "building tools for humans," aiming to create efficient development and debugging experiences.

Why React Hot Loader Was Created

Dan noticed a StackOverflow question about Webpack’s hot module replacement (HMR) and realized React could be combined with HMR in an interesting way. He recorded a short video showing a prototype that injected global variables into React’s source code. The video attracted many likes and followers, prompting him to build a real‑world implementation.

Initial Attempt: Using HMR Directly

HMR is a Webpack feature that allows modules to be updated without a full reload. In a typical setup you enable it in webpack.config.js or via the dev‑server CLI and call module.hot.accept('modulePath') in your code. When a module changes, HMR calls the provided callback.

module.hot.accept('./App', function () {
  const NextApp = require('./App');
  ReactDOM.render(<NextApp />, rootEl);
});

This simple approach works but does not preserve component state or DOM because the updated component is a new class instance, causing React to unmount the old one.

State and DOM Destruction Problem

When App.js updates, a new component type is created ( NextApp !== App ), so React unmounts the previous component, discarding its state and DOM. If the app stores all state in a single Redux store, you can persist the store (e.g., in localStorage ) and avoid this issue, but many apps still need component‑level state preservation.

Two Ways to Solve the Problem

Separate the React instance, DOM nodes, and state, creating a new component instance on each update and merging it with the existing DOM and state. This is not currently supported by React without using private APIs.

Proxy the component’s type so React believes the type has not changed. This is the technique used by React Hot Loader and React Transform.

Dan chose the second approach, building a separate project react‑proxy that wraps each component in a proxy class. The proxy forwards calls to the original component but can replace its implementation at runtime, preserving state and DOM.

Where the Proxy Is Applied

The proxy is injected via a Webpack loader. Although some think React Hot Loader is not a loader, it is called a loader because Webpack uses that terminology; other bundlers call similar tools "transforms." The loader finds exported components, wraps them in a proxy, and re‑exports the proxy.

Many people mistakenly think React Hot Loader is not a loader because it only implements hot reloading. This is a common misunderstanding 😊.

React Transform Emerges

React Transform was created to address limitations of the original loader, such as handling higher‑order components and functional components that were not detected by simple module.exports checks. It uses a Babel plugin to statically analyze source files, locate React components, and wrap them with transforms like HMR, error catching, etc.

Implementation Details

The Transform consists of five sub‑projects:

React Proxy – low‑level proxy implementation.

React Transform HMR – creates a proxy for each component and updates it on subsequent transforms.

React Transform Catch Errors – wraps render() in a try/catch to display a fallback UI.

Babel Plugin for React Transform – finds components during compilation and injects the chosen transforms.

React Transform Boilerplate – example project showing how to combine the pieces.

Because many components are exported as higher‑order components or functional components, the plugin must handle various export patterns, including default and named exports, class declarations, arrow functions, and React.createClass() calls.

React Hot Loader 3

React Hot Loader 3 builds on the proxy idea. It registers each component with a unique ID and replaces the component at runtime via a monkey‑patched React.createElement :

import createProxy from 'react-proxy';
let proxies = {};
const UNIQUE_ID_KEY = '__uniqueId';
export function register(uniqueId, type) {
  Object.defineProperty(type, UNIQUE_ID_KEY, { value: uniqueId, enumerable: false, configurable: false });
  let proxy = proxies[uniqueId];
  if (proxy) {
    proxy.update(type);
  } else {
    proxy = proxies[uniqueId] = createProxy(type);
  }
}
const realCreateElement = React.createElement;
React.createElement = function createElement(type, ...args) {
  if (type[UNIQUE_ID_KEY]) {
    type = proxies[type[UNIQUE_ID_KEY]].get();
  }
  return realCreateElement(type, ...args);
};

This approach works for both class and functional components because the proxy logic only needs to handle functions and classes, and the generated code is placed at the bottom of the bundle to avoid polluting source files.

Support for Compile‑to‑JS Languages

For languages like Elm or ClojureScript that compile to JavaScript, Dan also provided a Webpack loader ( react-hot-loader/webpack ) that registers exported components without Babel analysis, enabling hot reloading for those ecosystems.

Error Handling

React Transform includes a "catch‑error" transform that wraps component rendering in a try/catch . In newer React versions, error boundaries serve a similar purpose, and React Hot Loader is expected to adapt accordingly.

Conclusion

The article traces the history of React Hot Loader, explains the technical challenges of preserving state and DOM during hot updates, and shows how proxy‑based solutions and Babel transforms address those challenges. It also outlines the evolution toward React Hot Loader 4, which aims to stay closely aligned with future React releases.

References

Dan Abramov’s Medium article: https://medium.com/@dan_abramov/hot-reloading-in-react-1140438583bf

react‑proxy: https://github.com/gaearon/react-proxy

react‑transform‑hmr: https://github.com/gaearon/react-transform-hmr

babel‑plugin‑react‑transform: https://github.com/gaearon/babel-plugin-react-transform

react‑transform‑catch‑errors: https://github.com/gaearon/react-transform-catch-errors

react‑transform‑boilerplate: https://github.com/gaearon/react-transform-boilerplate

react‑hot‑loader: https://github.com/gaearon/react-hot-loader

frontendJavaScriptReActBabelwebpackHMRHot Loader
Hujiang Technology
Written by

Hujiang Technology

We focus on the real-world challenges developers face, delivering authentic, practical content and a direct platform for technical networking among developers.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.