How to Hot-Load React Component in 7 days. Part 2(React)

This article were written in 2017. Time heal the wounds:

^ this is an article from 2018 ^

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

So, you have just setup HMR (if no — go to part 1), and thinking — that`s next. How to use hot reloading in case of React.

It is soooo aweeeesoooome! You just edit your code in Editor, and WOW! page have been hot-patched and you see changes on the fly.
That awesome clip from that awesome article.

So, all I know about React Hot Code Reloading before — it just works. And with ease!

How do I estimate task about “enable HMR” for the first time?

3 lines of code. 0.5 story points.

At that estimation was almost correct. Almost.

If you have read some docs, followed guides, but nothing is working as expected — welcome to the club!

Step 1 — React Hot Loader

So, just after configuring HMR you have to add one new dependency to your project to convert HMR from module level to a component one.

react-hot-loader. Version 3.

So, as written in the migration guide:

  1. add new plugin into your babel configuration — react-hot-loader/babel
  2. add new file before your main files — react-hot-loader/patch
  3. wrap your application with AppContainer.

Thats all!

Babel plugin will prepare your code for React-HMR. Patch will actually patch React to support hot replacement. And AppContainer will force redraw of your application.

Step 2 — Cry out.

For a simple application — this will work. And, anyway, In 99.9% of cases it will preserve redux state.

But if you are “The Cool Programmer”, following best practices and use a lot of clean-and-ease-to-read pure functions, decorators and so on —

It will NOT work.

Just because there is a few limitations…..

  1. Patch uses a React-Proxy to wrap your components with Proxy and have ability to replace component without replacing component.
  2. Babel plugin sees only top level variables (webpack loader sees only exports).
  3. Yep, as long HoC, functional chains and compositions are using temporal variables — they are fucked out.
  4. There is no debug information.

Step 3 — Understanding a problem.

You have to understand a simple thing — there is no Santa, and there is no Magic inside React-Hot-Loadable.

  1. Babel plugin search for component declaration (all TOP LEVEL variables, classes and functions). Next it append new code to the end of file to call REACT_HOT_LOADER.register(class, exportedName, location) for each something it found.
  2. Next REACT_HOT_LOADER stores class with location reference in some WeakMap.
  3. If, at one day, slot will be occupied — so it means that you are performing hot update, and registering something new from an old location. And old instance must be replaced by a new one.
At this moment actual HRM happens. At last.

Ok. Lets write simple code

const superHoC = (something) => (Component) => (
<div>blabla <Component with={something} /></div>
const MySuperApplication = connect(mapStateToProps)(superHoC(withSomethingElse(SuperApplication)));

How many components you(and Babel) see here?

  • One component and one Higher-Order Component.

How many are there actually?

  • [SuperApplication], withSomethingElse(SuperApplication), superHoC(withSomethingElse(SuperApplication)), and connect(withSomethingElse(withSomethingElse(SuperApplication))).

At least 3. And 2 of them will be not founded by babel plugin, will be not registered for Patch, will be not wrapper with react-proxy, and will treated as brand new components on HMR event. As result:

Will cause remount. You will lose internal state.

Step 3 — fixing.

All you have to do, is to split functional chain into separate variables

const superHoC = (something) => (Component) => (
<div>blabla <Component with={something} /></div>
// each intermediate class as a separate variable.
const WithSomethingElse = withSomethingElse(SuperApplication);
const WithSuperHoc = superHoC(WithSomethingElse)
const MySuperApplication = connect(mapStateToProps)(WithSuperHoC);

So — just forget about modern functional style aka compositions. In this simple case babel plugin will see all parts, and will be able to update everything it have to update on HMR event.

PS: To say the truth — this rule solves almost all problems, including ones below….

So rule is a dumb simple

All parts of a component must be visible to a babel plugin. No function chains, no decorators. Only variables.

But please read that rule one more time.. And recall how you usually write higher order components. Lets check Facebook guide:

function logProps(WrappedComponent) {
return class InternalComponent extends React.Component {
componentWillReceiveProps(nextProps) {
render() {
// Wraps the input component in a container, without mutating it. Good!
return <WrappedComponent {...this.props} />;
const FinalComponent = logProps(MyComponent); // will work
const Component1 = connect(..)(logProps(MyComponent));// will not
const Component2 = connect(..)(FinalComponent);// will work

This example will work for a first case, as long plugin will see FinalComponent.

This example will work for a third case, as long plugin will see both FinalComponent and Component2(connect).

But it will not work for a second case — I did not store temporal class anywhere.

But this is to simple case.

function logProps(WrappedComponent) {
class InternalComponent extends React.Component {
componentWillReceiveProps(nextProps) {
render() {
// Wraps the input component in a container, without mutating it. Good!
return <WrappedComponent {...this.props} />;
const FinalClass = connect(mapStateToProps)(InternalComponent);
return FinalClass;

In this case you MIGHT have logProps as registered component, but InternalComponent will be hidden inside. And Proxy will not understand what are you doing, — as result whole nested tree will be remounted.

Remounted? In a few words — you will lose an internal state of components. And trigger unmount/mount on all nesting tree. Not the thing you need.

For example it will reset redux-form.

Step 4 — Proxy

The last thing you have to understand — is how Proxy and Patch works. And why you have to use AppContainer.

  1. Patch overload React`s createElement
  2. On element create it looking for a type inside registered components.
  3. If it is present — Patch will return Proxy. As result — softly wraps old component with a new one.

Proxy is a dirty hack. If you update proxy — you will update only proxy. Next you have to trigger an update. A forced one.

In some cases React Component, wrapped with React-Proxy will not react to props change. Cos props is an internal state of component, and type is not changed.

The next very important thing — that redraw will cause only redraw. You can only apply hot-patch to a render methods.

Just keep in mind — we are fighting with remounts. When we sussed — nothing will be mounted/dismounted. Half of your code will be not “hot” executed.

It is hard to explain, just wrap everything with AppContainer. And dont forget to perform whole page refresh time to time.

The only case for React Hot Loader — is to test small patches. Nothing more.

And the only thing you have to understand — Patch uses React.createElement.

Step 5— Higher-Order Components

So, to have your hi order components works you have to use createElement, not create a brand new class.

class InternalComponent extends React.Component {
componentWillReceiveProps(nextProps) {
render() {
const { WrapperComponent, props } = this.props;
return <WrappedComponent {props} />;
const ConnectedComponent = <-- is visible to babel
connect(mapStateToProps)(InternalComponent); <-- is visible to babel
function logProps(WrappedComponent) {
return (props) => <InternalComponent wrapped={WrappedComponent} props={props}/> <-- only creates a known component.

In this case you did not create a new class, you use other with custom props.

As result you will have not ONE smart HoC, but TWO sub components. And both should be visible to the Plugin.

Step 6— an easy way.

In the end you have keep in mind 2 things to use hi-order-components with react-hot-loader

  1. carefully design your components like I do in step 5.
  2. carefully extract each piece of your component into separate variables, like I do in step 3. With no internal intermediate components.
If you have HoC with connect inside — go to step#1. No other choise.

Very carefully in both cases. There is no build in debug in react-hot-loadable.

You can debug your code using alerts. Why not?

Step 7 — debugging

Ok. There is a way to debug RHL. I am going to open PR about it, but for now you can patch RHL by your own a bit.

  1. Open /node_modules/react-hot-loader/lib/
  2. find resolve class function.
  3. Patch it
function resolveType(type) {
// We only care about composite components
if (typeof type !== 'function') {
return type;

hasCreatedElementsByType.set(type, true);

// When available, give proxy class to React instead of the real class.
var id = idsByType.get(type);
if (!id) {
if (type) {
if (!visitedClasses.get(type)) {
console.log('[RHL] unknow class', type); <--- imposter!
visitedClasses.set(type, true)
return type;
var proxy = proxiesByID[id];
if (!proxy) {
return type;

return proxy.get();

And you will get an Error in case Patch is facing a new Component.

In normal situations you will see a lot of messages diring startup, as long all Components from node modules are not registered. But during reload — you have to see nothing.

Check your logs, and dig your code. Look luck.

Step 8 — DISABLE IT!!!

On Hot Load react-hot-loader will only re-render components. Also AppContainer will force everything to rerender.

AppContainer will even re-render pure components. Without props change.

As result — application behavior may differ from a real one.

Use HRM only for dev. Dont forget to check how your application works without it.

PS: And that about code splitting?

So — you are using best practices and using a code splitting in your project.

So will HRM work with deferred chunks… So HRM will work, but React-Hot-Loader…

The problem is simple. As always.

HMR will be triggered by chunk update, as long if you use that chunk — you are parent of it.

Next AppContainer will force redraw of all components.

Redraw. Not remount!

And tool you use to load deferred chunk — react-loadable, or react-universal-component, — will just render existing component. As long they are designed to load it only on mount. There is no mount.

Can you fix it? Nope. There is no way to fix existing components.

Lets write down a new one.

Long story short — I`v called it react-hot-component-loader.

The question is WHY it works. Everything is due this code

componentWillReceiveProps() {
// Hot reload is happening.
if ( {
remount() {
.then((payload) => {
this.setState({AsyncComponent: payload});

This code will catch the HMR event and replace internal AsyncComponent without entering loading state.

Without remounting nesting tree.

But, just after you loaded (at last) a new version of a component, and be ready to see a new version of it… So nothing will happens :)

Redraw of hot-replaced component must be driven by AppContainer. But it did its work and fall asleep.

But solution is also simply — wrap your AsyncComponent with a AppContainer.

if (AsyncComponent) {
return (
<AsyncComponent {...this.props} />

So — you can found react-hot-component-loader on github.

PS: react-universal-component can handle HRM, but I am not sure could it handle React-Hot-Loader.


Hot (re)loading is Amazing! It helps you to apply changes, and see them in a same environment.

But if you cannot preserve state on HMR event — it is better not to HMR.

It is very easy to preserve redux store, but preserve internal react states — much, much harder. Sometimes.

If you use MobX, i18n, function compositions, packs of HoC or something else — React Hot Loadable will not work as expected. And sometimes — there is no way to fix it.

Then I first time met React Hot Loader (it was 2(two) days ago) I expect that everything will be quite simple. As seen on TV. Ha!

By the end of a day I was busted. I lose trust in webpack, in react, in people.

I have read a lot of articles, understand sources, find possible ways…

And by the end of a second day write this article :P

It is amazing, but there is no easy description why RHL works as it works and how to change your code to fit this library expectations.

Yet again — you have to change your own code.

Or develop a bit more usable babel plugin or even browser extension.

That`s all, I hope you will found a few stupid answers to a few stupid questions. But if not, or if they will not help you — just forget about HMR, live of sweet even without it.

PS: Why I call this topic like a “In 7 days” but did everything in 2?

This is not the end.

State tuned.

PS: 5 days later I`v appended article with AsyncComponentLoader case.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.