1. 17
    Hot Reload a React App in Development with react-hot-loader
    6m 23s

Hot Reload a React App in Development with react-hot-loader

Andy Van Slaars
InstructorAndy Van Slaars

Share this video with your friends

Send Tweet
Published 4 years ago
Updated 3 years ago

Generating new bundles when we change files is a great start, and the live-reload provided by webpack dev server is convenient, but a reload means we lose our application state. When you want to see the results of minor adjustments while your application is in a specific state, it would be more convenient if we could have our changes reflected without losing that state. In this lesson, we'll add hot reloading to our development webpack server so our changes will be reflected in the browser when we save new changes, without the need to a refresh.

Instructor: [00:00] I'm running this application with webpack dev server. When I make a change to the code and save it, it'll trigger a reload in the browser. If I were to come in here, change our greeting, and save that, you'll see that the browser's going to refresh, and our changes are going to be reflected.

[00:15] This is a stateful application. If I come in here, and I increment this counter, we'll see that it's updating, and that count value is being stored in the local state for the application.

[00:26] Let's say I'm working with my application, I've changed my local state, and I make a change. We'll change the greeting back, and I save that. The browser's going to reload, and I'm going to lose that state.

[00:40] In a lot of cases, this behavior is just fine. But sometimes, you might be changing something that relies on that state, and we just want to iterate on that feature until we get it right without having to reset our state.

[00:50] Let's put a simple example in our code of something that relies on state that we may want to iterate on. I'm going to come down here, and I'm just going to break this h2 out into a few lines. In this opening h2 tag, I'm going to add a classname attribute.

[01:05] This classname is going to be dependent on the count. In style.css, I've added this warning class. I want to apply that to this h2 only when the count hits a certain threshold. We're going to come in here, and we're going to say if the count is greater than 10, then our classname is going to be warning.

[01:29] Otherwise, we'll just return null here, and I'll save this. Our browser will reload, and then I'm going to come in here. I'm going to increment the counter until we hit 11, and we'll see that now, this is showing in red.

[01:43] Let's say we don't really like this red. I'm going to come into styles.css, and we're going to change this to a slightly less stark red. I'm going to save that. Now the browser's going to reload, and I'm going to lose my count.

[01:58] To see that change reflected, I'm going to have to go back in and click the button a bunch of times to get my state back to where it was. Now you can imagine, in a more complex application, getting our state back to a certain point might take more than just clicking a button a handful of times.

[02:14] This is something that in certain cases, it would be nice to be able to avoid that full reload of the browser. Let's go back into our terminal. I'm going to stop webpack-dev-server with Control+C. Then I'm going to do an npm i -s to save this is a dependency.

[02:30] We're going to install a package called react-hot-loader. With that installed, we have some configuration to do. I'm going to reveal my files here, and I'm going to find my webpack config base. react-hot-loader actually includes a Babel plugin.

[02:51] We're going to include that here. I'll just break these out. We're going to add react-hot-loader/babel as a Babel plugin. Then I'm going to go into my app.js. At the top of the file, I'm going to add an import of hot from react-hot-loader.

[03:24] I'm going to drop to the bottom of the file, where I'm doing my export. My export default, instead of just exporting app, I'm going to make this a call to hot, which is going to receive an argument called module.

[03:38] That's going to return a function. Then we're going to call that function, passing in app. The double parens here just means that this gives us back a function, and then we call that function with app as an argument.

[03:50] If it makes more sense to break it up, we can do this, where then we call this function here. It does essentially the same thing. I'm going to leave it to one line, like this.

[04:11] We'll save that. Then I'm going to open up my package.json. I'm going to take this dev script, and I'm going to duplicate it.

[04:22] I'm going to create a second script that I'm going to call dev:hot. This is going to do the same thing. It's going to run webpack-dev-server. We'll call the open flag. We'll use our dev config, but I'm going to pass an additional flag here, --hot.

[04:39] We can save that. Now I can bring my terminal back up, and I'm going to run npm run dev:hot. This is going to open a new browser window. There's my application.

[04:56] Now I'm going to come into app. Let's make a quick change just to see what happens.

[05:01] I'll throw a few more exclamation marks there, and I'm going to save this. We're going to see the browser updates without doing a reload. What happens if I change my state, and then I make a change in my code?

[05:13] I'll increment that count, and I'll remove all the exclamation marks. I'm going to save this. If we look at the browser, we'll see that that change has been reflected, but my local state has been maintained. If we go back to our original use case, where I increment the count, and then I want to make some changes to this CSS, I can come in here.

[05:34] I can change that, and we'll see it reflected in the browser without having to manually reset our state. You'll notice if we look at the terminal while changes are happening, that these hot update JSON chunks are created.

[05:48] If we look in the browser, and we look at the console, we'll see that we have this hot module reload checking for updates. These updates are being sent into the browser using web sockets, and then the code is swapped at runtime.

[06:03] To recap -- most of the time, the live reload of the browser is going to be just fine. If you're trying to iterate on something that requires a manual update to get to the state you need the app to be in, then using hot reloading is a good option.

[06:16] This is why we separated the scripts in package.json, so you can do a normal dev setup, and then run dev:hot when you think you need it.

Artificial Labs
Artificial Labs
~ 3 years ago

Can you please explain why you do not install react-hot-loader as a dev-dependency? I saw some examples on the web where import {hot} ... was not used, and instead if (module.hot)... was used along with slightly different implementation (module.hot.accept(...), etc.) What do you think of this kind of approach in regards to installing react-hot-loader as a dev-dependency? I am also wondering what implications of using react-hot-loader as a dev-dep you would see in terms of having react-hot-loader/babel in .babelrc as an element in plugins array - instead of having it in dev-related webpack config. I checked the production build of my project (with react-hot-loader as a dev-dep) and it went fine.

Petros Kyriakou
Petros Kyriakou
~ 3 years ago

@Artificial Labs, if you check the github page of react-hot-loader it says this

"Note: You can safely install react-hot-loader as a regular dependency instead of a dev dependency as it automatically ensures it is not executed in production and the footprint is minimal."

So its safe to be used as a normal dependency

mark connelly
mark connelly
~ 3 years ago

I was following along in a windows based environment and output was not showing when the code changed from Count: {this.state.count} to Count: {count}.

using this code instead had me up and running again.

        <h2 className={this.state.count > 10 ? 'warning' : null}>
            Count: {this.state.count}
        </h2>
Rahil
Rahil
~ 3 years ago

why isn't module undefined here, I checked my console and module is actually an object. Please inform where does this module object come from?

Andy Van Slaars
Andy Van Slaarsinstructor
~ 3 years ago

why isn't module undefined here, I checked my console and module is actually an object. Please inform where does this module object come from? module comes from webpack. You can read more about it here: https://webpack.js.org/api/module-variables/#module-hot-webpack-specific-

Andy Van Slaars
Andy Van Slaarsinstructor
~ 3 years ago

I was following along in a windows based environment and output was not showing when the code changed from...

@mark - are you missing the line at the top of the render method where state is destructured: const {count} = this.state?

The OS you're developing on shouldn't change this behavior.

Doma
Doma
~ 3 years ago

Hi Andy,

First of all, I'd like to thanks for such a great tutorial. I have 2 questions in this section.

  1. Why not just use webpack default HotModuleReplacementPlugin instead of react-hot-loader?

i.e. ./webpack.config.dev.js ... +const webpack = require('webpack')

module.exports = merge(baseConfig, { mode: 'development', devServer: { port: 9000, hot: true }, devtool: 'source-map',

  • plugins: [new webpack.HotModuleReplacementPlugin()] })

./src/index.js

if (module.hot) { module.hot.accept('./App', () => { ReactDOM.render(<App />, document.getElementById('app')) }) }

  1. What if I need to connect redux store and hot reload? Can you simplify a demo?

Thanks. Darren

2359 Media
2359 Media
~ 3 years ago

Hi Andy,

Just want to ask, where did the --watch go?

Thanks

Hafeez Syed
Hafeez Syed
~ 3 years ago

Hi Andy,

Is there a way to get HMR work for CSS changes as well ?

When I make changes to .css files, the browser reloads instead of just changing the styles.

Thanks

Federico Hatoum
Federico Hatoum
~ 3 years ago

@Kane, In lesson 13 Andy replaced the "dev" script call in package.json with webpack-dev-server which automatically does a --watch.

Ahmed Soliman
Ahmed Soliman
~ 3 years ago

Why is react-hot-module a babel plugin not a webpack plugin ?