This is a minimal example of hot module replacement (or HMR) in a Redux application. The working demo code is hosted on GitHub. We only include those settings essential to support HMR, making you easy to apply HMR in your own Redux application.

If you cannot wait to apply HMR, jump to this section to set up HMR for your project within five minutes!

Hot module replacement demonstration

Run the Example

Get your hands dirty first! Before you run the commands to start this example application, please ensure that Git, Node.js, and Yarn are installed correctly on your machine.

$ git clone https://github.com/Front-end-io/articles.git
$ cd articles && git checkout redux-hmr
$ yarn install
$ yarn start

Then visit http://localhost:3000/ to see if it works.

Upon writing your code, hot module replacement is able to update the page without a full refresh. More importantly, the Redux state is kept while other resources have been updated in place.

Hot Module Replacement

Hot module replacement is one of the most useful features offered by Webpack. It allows all kinds of modules, including JSON, CSS, and JS files, to be updated at runtime without needing a full refresh.

Here is how it works internally:

  1. The application asks the HMR runtime to check for updates.
  2. The runtime asynchronously downloads the updates and notifies the application.
  3. The application then asks the runtime to apply the updates.
  4. The runtime synchronously applies the updates.

Hot module replacement diagram

HMR boosts productivity when developing a Redux application. Redux is a predictable state container for JavaScript apps. It’s a very popular state-of-art framework based on React. Redux, by definition of the first principle of Redux, is a singular shared data store, described by its documentation as a “Single source of truth.” The data store (a plain JavaScript object updated by reducers) will be updated as the user operates on the application. Every user operation, such as clicking a button, loading back-end data, etc., will likely update the store multiple times. It’s not easy to fix a bug when the bug happens only with a particular snapshot of the state.

HMR allows us to update the page without re-initializing the global store. During Redux development, we may want to inspect the store after a series of operations. A very common scenario is, a bug occurs only after we have added a particular (maybe complex) item to the store. Without HMR, we have to do the following steps:

  1. Modify the code that potentially causes the bug.
  2. Refresh the page, add the particular item to the store.
  3. If the bugs persist, repeat Step 1.

The above iteration will be repeated again and again if the bug is difficult to find. In the real world, the bug may only appear after even more operations. HMR helps us to compile and apply the modified code while keeping the current store value unchanged. We do not need to repeat Step 2. It boosts the efficiency of development.

Correcting a bug does not mean you have to restart the application, with HMR.

Note: In some cases, the code modification may affect the current store value. In that case, HMR will warn you to reload the entire page.

Feature in This Example

We want to keep the feature minimal, just to demonstrate the HMR capability. So in this application, we do not incorporate common features in a React application, including redux-logger, react-router-redux, redux-thunk, redux-devtools, etc. Meanwhile, we keep only one reducer, two actions, and 1 page.

Our application keeps only a counter value in the store. We have only one page called home, which displays the counter value and two buttons to increase/decrease the counter value.

To confirm that HMR works, simply increase/decrease the counter multiple times, then modify some code at src/js/components/home.js. For example, modify the title Counter to Counter in store. Then we will find that:

  • The page is not refreshed.
  • The displayed counter value is NOT CHANGED.
  • The title has been changed to Counter in store.

Set Up HMR in Five Minutes

To set up HMR, follow these steps.

Essential Libraries

These libraries must be installed to support HMR:

ES6

If you are using ECMAScript6 (Who isn’t, these days?), you need some more tools to compile ES6 in real time. First, this is the minimal ES6 config file .babelrc:

{
  "env": {
    "development": {
      "presets": [
        "react-hmre"
      ]
    }
  }
}

To support real-time compilation, this library is needed:

Webpack.config.js

We need to configure HMR in the Webpack configuration file webpack.config.js.

Firstly, enable the HMR plugin in the plugins section:

"plugins": [
  …  
  new webpack.NamedModulesPlugin(),
  new webpack.HotModuleReplacementPlugin(),
]

The HMR plugin generates a Manifest, a JSON file listing the updated modules, and an Update, a JSON file containing the data to be applied. What to be noted is, HMR is an option provided by Webpack. Loaders like style-loader, which implement the HMR interface, receive an update through HMR and then replace the old code with the new code.

If we are using webpack-dev-server, then we need to turn on the hot flag in the devServer section:

"devServer": [
   ...
  hot: true,
]

Hot Reload the Redux Reducers

Starting from Redux version 2.0.0, the reducers are not hot reloaded implicitly because the implicit hot reloading causes some problems. If your Redux state is reset to initial values when hot updated, try to enable hot update for the reducers:

import { createStore } from 'redux';
import rootReducer from '../reducers/index';

export default function configureStore(initialState) {
  const store = createStore(rootReducer, initialState);

  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers', () => {
      const nextRootReducer = require('../reducers/index');
      store.replaceReducer(nextRootReducer);
    });
  }

  return store;
}

Advanced Settings

For more advanced settings of HMR, please refer to the HMR API.

Run

Finally, please run the application with:

$ ./node_modules/.bin/webpack-dashboard -- webpack-dev-server

Troubleshooting

HMR Simply Does Not Apply the Changes

HMR may fail silently without any warnings. When you update the code and save, the page simply does not update at all. This is probably because your system does not allow you to watch so many file changes.

On Ubuntu, you can run sysctl -a | grep inotify to view the current user.max_inotify_watches value. Try to increase this number by running: sudo sysctl fs.inotify.max_user_watches=524288. Alternatively, append a new line fs.inotify.max_user_watches=524288 to file sudo vim /etc/sysctl.conf and then run sudo sysctl -p /etc/sysctl.conf to apply the change.

Understanding the Basics

What is the Redux framework?

Redux is a JavaScript library used for managing application states by implementing predictable state containers. It is used to build user interfaces in a stable and consistent way.

About the author

Shaojiang Cai, China
member since February 24, 2016
Shaojiang is a passionate front-end developer with seven years of professional experience. He loves JavaScript, especially React and Redux. He has extensive experience in large-scale data visualization (D3.js). His skill set covers Angular, Node.js, ES6, jQuery, React, D3, Sass, Gulp, Webpack, and Git. He is also an active StackOverflow reviewer and GitHub developer. [click to continue...]
Hiring? Meet the Top 10 Freelance JavaScript Developers for Hire in August 2018

Comments

Alexey Lunacharsky
Great article thanks for sharing. After working with Clojurescript/Figweel couple of years ago I was dreaming about having it in JS, and finally thanks to redux it's possible! BTW would it work with Node.js?
Alex Seitsinger
react transform hmr was deprecated in favor of react hot loader. Hot reloading can be accomplished by following the instructions found on that github: https://github.com/gaearon/react-hot-loader.
Shaojiang Cai
Thanks. Yes, HMR is possible at server side: https://github.com/webpack/docs/issues/45 https://github.com/webpack/docs/wiki/hot-module-replacement#examples
Shaojiang Cai
Thanks Alex. Yes, this blog article is up-to-date. Maybe you referred to the GitHub page which is outdated. I will update there as well.
Jose Galdamez
This information will become very handy when I start a project using bare Webpack, React, and Redux. I typically start with Create React App which hides the Webpack configs. While ejecting from CRA is an option, I’ve found it easier to do HMR with a config override. I’ve yet to run into problems with Redux and HMR, but if I do I know I can hot reload redux reducers as shown here.
Alex Shchur
Hey @shaojiangcai:disqus , nice article. Is the approach you describe based on react-hot-loader basically an alternative to this one https://github.com/webpack-contrib/webpack-hot-middleware ?
comments powered by Disqus
Subscribe
Free email updates
Get the latest content first.
No spam. Just great articles & insights.
Free email updates
Get the latest content first.
Thank you for subscribing!
Check your inbox to confirm subscription. You'll start receiving posts after you confirm.
Trending articles
Relevant Technologies
About the author
Shaojiang Cai
JavaScript Developer
Shaojiang is a passionate front-end developer with seven years of professional experience. He loves JavaScript, especially React and Redux. He has extensive experience in large-scale data visualization (D3.js). His skill set covers Angular, Node.js, ES6, jQuery, React, D3, Sass, Gulp, Webpack, and Git. He is also an active StackOverflow reviewer and GitHub developer.