
Hot reloading components in React
I have two favorite requests in Google:
- What will happen if you throw scrap into the toilet of a train at full speed?
- What will happen if the component is replaced in full swing in the reaction?
And if everything is more or less clear with the first question, then with the second question everything is not so simple - Webpack-dev-server, Hot Module Replacement, and React-Hot-Loader immediately get out.
And everything would be fine, but this explosive mixture simply does not work, stumbling on the first complex code, HOC, composition, decorator and native arrow functions.
In general, the third version of Reac-hot-loader was not launched at all.

In fact, version 3 had 3 problems:
- react-proxy, which was used to "replace" the old version of the component with a new one, and which was not at all friendly with arrow functions, to which the context is nailed tight.
- to ensure the operation of bound and transpiled arrow functions babel plugin wrapped them in intermediate functions. Given that he did this for ALL classes - often this led to breakdowns. Those generally did not work.
- The very principle of search and substitution of components. To do this, we used the babel plugin, which “registered” all the top-level variables, so that later we could understand that “this variable” is actually a “BigKonka” and the proxy should be updated.
Everything would be fine, but the HOC can create a class inside itself, and the decorator simply “decorates” the real variable. As a result, the react-reconciler, upon rendering, will meet a “completely new” class in place of the old one and will unmount the whole old tree.
Popular wisdom says :
In other words - without a normal preserve state, what for this RHL is not needed.
My journey to RHL began six months ago, when I spent about a week (a lot of it) trying to understand how people used React-hot-loader all these years because using it is unbearably painful. He brings nothing but pain. And then he opened PR, which silently began to prompt why and where RHL would unmount the component so that people could finally understand why it wasn’t working. In order to somehow alleviate mental suffering.
And then I decided to fix everything in the bud.
I’ll be brief - version 4 almost always works. She still has limitations that stem from the very nature of the phenomenon, but these “mistakes” are the guarantor of the correctness of the work. You can try it now, just upgrade RHL to version 4.
HMR is a hot swap module. Built-in webpack and parcel mechanism that allows you to update individual modules on the client when they change on the server. Just do not forget - this is exclusively about the development. Without additional gestures, he will silently reject the page.
RHL is a react-hot-loader, a set of measures aimed at ensuring that React simply renders the updated element and does nothing else.
RHL is something that provides the “correct” HMR in the form in which it is needed.
1. Instead of react-proxy, react-stand-in is used - a slightly more “javascript” solution. The main difference - standin is not a “wrapper”, and not a proxy — it is a class that inherits from the real one.
The second tricky moment is the transfer of changes made in the constructor (including those added to the constructor by the babel). Standin instantiates an old and new class, after which it searches for changes and tries to repeat them.
As a result, after updating the component, all changes are applied, except for those made in componentWill / DidMount. Because mount / unmount did not occur, and it was precisely this that was required to be avoided.
2. Instead of “registrations” that are not friends with the HOC and decorators, a mechanism called “hotReplacementRender” is used.
When the moment of “update” of the components comes, React-Hot-Loader saves the old tree and starts to render the new one.
After rendering each element, there comes a moment of "comparing" old and new data, in fact a reconciler.
This approach easily breaks through any compositions, decorators, and generally any render-props. The only moment that does not worry is a change in the number or sequence of children (if no key is specified), but this follows from the very nature of React.
3. Previously, many people stumbled on the moment of setting up HRM and RHL. In the new version, all configuration is limited to _one_ command.
The magic of hot (module) (MySuperApplication) will automatically configure HMR for the current module, and the HOC part of this function will wrap MySuperApplication in the AppContainer.
ALL! (Plus babel-plugin don't forget)
Where does it work? Everywhere - Webpack, parcel, typescript (do not forget the babel-plugin). There are examples for everything.
1. RHL v3 wrapped in proxies only "registered" components. v4 wraps absolutely everything. Theoretically, this should not affect productivity, but anything can happen.
2. Hot configures the current module as self accepted. Here you need to understand that nothing but the "react component" that RHL can survive can not be exported from the module.
Errors now standard:
- use hot for local variables or in general in rendering (detective and swear)
- use hot for HOC and functions - everything breaks silently.
Hot - _only_ for components.
3. If you started the timer in componentDidMount, and then changed the function that this timer calls, it will not be updated. Because setTimeout already received a link to the function, and you can’t change it.
4. Code splitting - it is required either to wrap each component that you are going to dynamically load in hot, then it will update itself, or use a “loader” that is familiar with HMR / RHL.
- The popular react-lodable is basically not suitable. If you have one - there are no other options, except how to wrap components in hot - no. (do not forget that this does not affect production in any way)
- loadable-components are slightly better - they will try to update the file, but there may be problems, since “hotReplacementRender” will already be turned off when import works.
- 100% react-imported-component works well , since it wraps the wrapped component in the AppContainer, and this "saves" the situation, but its SSR is a bitspecific , and not for everyone.
5. I think this is far from the end.
React-hot-loader is not a silver bullet - but rather a highly specialized tool that can be very useful. It may not be.
Right now we are close to releasing the RC version. It’s corny no longer to fix bugs and add features. Only a little code coverage to raise.
Now is the time to install RHL for yourself, and try it out. And to report all the problems that should arise (of course!) Should not: D
In general - fire!
- What will happen if you throw scrap into the toilet of a train at full speed?
- What will happen if the component is replaced in full swing in the reaction?
And if everything is more or less clear with the first question, then with the second question everything is not so simple - Webpack-dev-server, Hot Module Replacement, and React-Hot-Loader immediately get out.
And everything would be fine, but this explosive mixture simply does not work, stumbling on the first complex code, HOC, composition, decorator and native arrow functions.
In general, the third version of Reac-hot-loader was not launched at all.

Preamble
In fact, version 3 had 3 problems:
- react-proxy, which was used to "replace" the old version of the component with a new one, and which was not at all friendly with arrow functions, to which the context is nailed tight.
- to ensure the operation of bound and transpiled arrow functions babel plugin wrapped them in intermediate functions. Given that he did this for ALL classes - often this led to breakdowns. Those generally did not work.
- The very principle of search and substitution of components. To do this, we used the babel plugin, which “registered” all the top-level variables, so that later we could understand that “this variable” is actually a “BigKonka” and the proxy should be updated.
Everything would be fine, but the HOC can create a class inside itself, and the decorator simply “decorates” the real variable. As a result, the react-reconciler, upon rendering, will meet a “completely new” class in place of the old one and will unmount the whole old tree.
Popular wisdom says :
One of the most annoying things to setup with Webpack is a properly working Hot Module Replacement. Working properly means that components will keep their local state. Everything else makes HRM uselss (in my opinion).
In other words - without a normal preserve state, what for this RHL is not needed.
My journey to RHL began six months ago, when I spent about a week (a lot of it) trying to understand how people used React-hot-loader all these years because using it is unbearably painful. He brings nothing but pain. And then he opened PR, which silently began to prompt why and where RHL would unmount the component so that people could finally understand why it wasn’t working. In order to somehow alleviate mental suffering.
And then I decided to fix everything in the bud.
Meet version 4!
I’ll be brief - version 4 almost always works. She still has limitations that stem from the very nature of the phenomenon, but these “mistakes” are the guarantor of the correctness of the work. You can try it now, just upgrade RHL to version 4.
What is HMR, RHL and all that?
HMR is a hot swap module. Built-in webpack and parcel mechanism that allows you to update individual modules on the client when they change on the server. Just do not forget - this is exclusively about the development. Without additional gestures, he will silently reject the page.
RHL is a react-hot-loader, a set of measures aimed at ensuring that React simply renders the updated element and does nothing else.
RHL is something that provides the “correct” HMR in the form in which it is needed.
There is an alternative theory that HMR leads to monkey-patching, better TDD, BDD and all that. And there is such a big drop of truth in it.
Differences of version 4 from version 3
1. Instead of react-proxy, react-stand-in is used - a slightly more “javascript” solution. The main difference - standin is not a “wrapper”, and not a proxy — it is a class that inherits from the real one.
This is a very tricky moment - when it comes time to replace one component with another - standin will simply change its prototype (more precisely, the prototype of its prototype).
Result - this never changes.
The second tricky moment is the transfer of changes made in the constructor (including those added to the constructor by the babel). Standin instantiates an old and new class, after which it searches for changes and tries to repeat them.
As a result, after updating the component, all changes are applied, except for those made in componentWill / DidMount. Because mount / unmount did not occur, and it was precisely this that was required to be avoided.
2. Instead of “registrations” that are not friends with the HOC and decorators, a mechanism called “hotReplacementRender” is used.
When the moment of “update” of the components comes, React-Hot-Loader saves the old tree and starts to render the new one.
After rendering each element, there comes a moment of "comparing" old and new data, in fact a reconciler.
If the new component is "very similar" to the old one - maybe this is it, and you can replace it.
This approach easily breaks through any compositions, decorators, and generally any render-props. The only moment that does not worry is a change in the number or sequence of children (if no key is specified), but this follows from the very nature of React.
3. Previously, many people stumbled on the moment of setting up HRM and RHL. In the new version, all configuration is limited to _one_ command.
import React from 'react';
import {hot} from 'react-hot-loader';
const MySuperApplication = () => ......
export default hot(module)(MySuperApplication); <-----
The magic of hot (module) (MySuperApplication) will automatically configure HMR for the current module, and the HOC part of this function will wrap MySuperApplication in the AppContainer.
ALL! (Plus babel-plugin don't forget)
Where does it work? Everywhere - Webpack, parcel, typescript (do not forget the babel-plugin). There are examples for everything.
Features of work that you should know about
1. RHL v3 wrapped in proxies only "registered" components. v4 wraps absolutely everything. Theoretically, this should not affect productivity, but anything can happen.
2. Hot configures the current module as self accepted. Here you need to understand that nothing but the "react component" that RHL can survive can not be exported from the module.
Errors now standard:
- use hot for local variables or in general in rendering (detective and swear)
- use hot for HOC and functions - everything breaks silently.
Hot - _only_ for components.
3. If you started the timer in componentDidMount, and then changed the function that this timer calls, it will not be updated. Because setTimeout already received a link to the function, and you can’t change it.
4. Code splitting - it is required either to wrap each component that you are going to dynamically load in hot, then it will update itself, or use a “loader” that is familiar with HMR / RHL.
- The popular react-lodable is basically not suitable. If you have one - there are no other options, except how to wrap components in hot - no. (do not forget that this does not affect production in any way)
- loadable-components are slightly better - they will try to update the file, but there may be problems, since “hotReplacementRender” will already be turned off when import works.
- 100% react-imported-component works well , since it wraps the wrapped component in the AppContainer, and this "saves" the situation, but its SSR is a bitspecific , and not for everyone.
5. I think this is far from the end.
React-hot-loader is not a silver bullet - but rather a highly specialized tool that can be very useful. It may not be.
Time to try?
Right now we are close to releasing the RC version. It’s corny no longer to fix bugs and add features. Only a little code coverage to raise.
Now is the time to install RHL for yourself, and try it out. And to report all the problems that should arise (of course!) Should not: D
In general - fire!
github.com/gaearon/react-hot-loader/tree/next
npm install react-hot-loader @ next