JS preacher. Developer 🥑. Building the web with the community @concatenateConf @forLoopAfrica. JS & Senior Advocacy for the Next Billion Users thru @Microsoft

Several years ago, it was becoming tiring (and annoying in the case where the changes do not render as expected) to refresh the browser to see the most recent updates on a web project.

In a bid to solve this problem, developers created several plugins and tools that can cause the DOM to re-render on each save without even doing a full-reload.

This is called hot reloading. It works by replacing a module of the application during runtime with an updated one so that it’s available for instant use.

This leads us to talk about Hot Module Replacement (HMR).

HMR, as the name implies, can replace modules without restarting the server and can easily be enabled with different bundlers.

On webpack’s website, it says:

Hot Module Replacement (HMR) exchanges, adds, or removes modules while an application is running, without a full reload. This can significantly speed up development in a few ways.

HMR solves the problem of hot reloading, makes it easier to tweak styling (almost comparable to changing styles in the browser’s debugger) and generally speeds up the development process.

But what happens when we live reload in a component based framework like React that keeps track of its states? We lose the state.

The reason we lose the state can be understood by first understanding the difference between hot reload and live reload:

A hot reload to an app will only refresh the files that were changed without losing the application’s state.

to an app will only refresh the files that were changed without losing the application’s state. A live reload to an app will restart the entire app, and load cause it to lose its state.

The primary aim of this tutorial is to demonstrate how we can quickly setup react-hot-loader for our React application so that its components can be live reloaded without a loss in state.

The resulting code for this article is available here on GitHub.

Prerequisites

Please ensure that you have Node and npm installed before starting the tutorial Very basic knowledge of React is assumed, and a general understanding of JavaScript would be helpful We will be using the create-react-app tool to create the React application

If you don’t already have the create-react-app tool on your computer, you can install it with this command:

npm install -g create-react-app

Set up the development environment

Let’s spin up a new instance of a create-react-app project and navigate into the newly created directory with these commands:

create-react-app react-hot-loader-demo cd react-hot-loader-demo

We can run the application using this command:

npm start

This command starts the web server that points to the address localhost://3000 . We will visit this address on our browser and keep the tab open because throughout this tutorial, we will be monitoring the updates and behavior of the application in the browser.

When we create a new project using the create-react-app , the HMR plugin is enabled by default in the webpack configuration file, though we can’t see this file because create-react-app configures our application for us and hides the configuration files.

Checking the hot reload behavior

We can see the HMR’s hot reloading in action by adding a basic style to the index.css file that’s included out of the box. We’ll add a property value pair — background: lightblue — to the body style:

body { margin: 0; padding: 0; font-family: sans-serif; background: lightblue; }

On saving this, the application updates without the browser tab refreshing.

This behavior is possible because the HMR is able to replace a module of code in the application during runtime.

Checking the hot reload behavior with a JavaScript file

Now let’s see what happens when we edit the content in the App.js file, we can do something as basic as replacing the “To get started, edit src/App.js and save to reload” with “This is a tutorial to setup React Hot Loader.”

import React, { Component } from 'react'; import logo from './logo.svg'; import './App.css'; class App extends Component { render() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1 className="App-title">Welcome to React</h1> </header> <p className="App-intro"> This is a tutorial to setup React Hotloader.. </p> </div> ); } } export default App;

This time, it can be observed that the application does a live reload and the entire page refreshes so that the change can be implemented. This happens because the HMR is unable to decide how to handle the update to this JavaScript file.

Naturally, hot reloads are possible when the HMR receives an update at runtime and confirms that the concerned module knows how to update itself. Where the module knows how to update itself, the HMR then goes up the import/require chain, searching for a parent module that can accept the update.

Let’s tweak our application a bit so that the HMR knows how to handle JavaScript files for hot reloads.

In the index.js file (which is the entry point of our application), we will add this line of code:

if(module.hot){ module.hot.accept() }

This code will make it possible for the updates to our React components to do hot reloads because the parent module ( index.js ) now knows how to accept and process the runtime updates.

Now, lets make a quick edit to the code and save it to see if the state persists, we will replace Will the state be preserved? The value is {this.state.number} with “Does the state persist now? The value is {this.state.number}” :

import React, { Component } from 'react'; import logo from './logo.svg'; import './App.css'; class App extends Component { render() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1 className="App-title">Welcome to React</h1> </header> <p className="App-intro"> This update will not cause a refresh to the browser tab. </p> </div> ); } } export default App;

The resulting page:

This update is handled as a hot reload and didn’t cause the browser to refresh!

Checking the hot reload behavior with a state variable

Everything we have done has been awesome so far. Let’s see what happens when we include a basic state variable to the application, we can also add a function to make it increment on click events:

import React, { Component } from 'react'; import logo from './logo.svg'; import './App.css'; class App extends Component { constructor(props){ super(props); this.state = { number : 0 } } render() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1 className="App-title">Welcome to React</h1> </header> <p className="App-intro"> The current value of number is {this.state.number} </p> <button onClick={()=>this.setState({number : this.state.number + 1})}>+</button> </div> ); } } export default App;

When we save this code and it hot reloads, we can click on the buttons 12 times to increment it:

It works just as we wanted it to, however, what happens if we make an edit to the JavaScript file and save it now? It should do a hot reload just as before and also preserve the value of the state variable, right? Let’s see about that. Let’s replace the line The current value of number is {this.state.number} with Will the state be preserved? The value is {this.state.number} :

import React, { Component } from 'react'; import logo from './logo.svg'; import './App.css'; class App extends Component { constructor(props){ super(props); this.state = { number : 0 } } render() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1 className="App-title">Welcome to React</h1> </header> <p className="App-intro"> Will the state be preserved? The value is {this.state.number} </p> <button onClick={()=>this.setState({number : this.state.number + 1})}>+</button> </div> ); } } export default App;

On saving it, we get this screen:

What just happened? Wasn’t our number equals to twelve a few seconds ago? Where did that value go? That’s right, during the hot reload, the component unmounted and the constructor had to re-run when the component was mounted again. We lose state data even with the hot reload features HMR gives to us.

We can handle this issue using the React Hot Loader plugin and doing some configurations.

Setting up React Hot Loader

First of all, we want to eject our application so we can customize its configuration:

npm run eject

Running npm run eject copies all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc.) right into your project so you have full control over them. Commands like npm start and npm run build will still work, but they will point to the copied scripts so you can tweak them. Doing this is also permanent.

Next, we pull in React Hot Loader, which is a plugin that allows React components to be live reloaded without the loss of state. It works with webpack and other bundlers that support both HMR and Babel plugins.

npm install --save react-hot-loader

Linux users might need to prefix this command with sudo for permission reasons.

When this is done installing, we want to navigate into the config/webpack.config.dev.js that is now available to us, add this line — plugins: ['react-hot-loader/babel'] — to the Babel loader configuration. This is what it should resemble:

// Process JS with Babel. { test: /\.(js|jsx)$/, include: paths.appSrc, loader: require.resolve('babel-loader'), options: { // This is a feature of `babel-loader` for Webpack (not Babel itself). // It enables caching results in ./node_modules/.cache/babel-loader/ // directory for faster rebuilds. cacheDirectory: true, plugins: ['react-hot-loader/babel'], }, }

The next thing we want do is open our application’s entry point again and wrap the app’s top-level component inside of an <AppContainer> . We have to import import the <AppContainer> from react-hot-loader first:

import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import registerServiceWorker from './registerServiceWorker'; import { AppContainer } from 'react-hot-loader'; ReactDOM.render( <AppContainer> <App /> </AppContainer>, document.getElementById('root')); registerServiceWorker(); if(module.hot){ module.hot.accept() }

Let’s modify the module.hot section so that we can also render the <AppContainer> within it:

if(module.hot){ module.hot.accept('./App', () => { const NextApp = require('./App').default; ReactDOM.render( <AppContainer> <NextApp /> </AppContainer>, document.getElementById('root') ); }); }

This modification tells the <AppContainer> to process the module reloading and handle any errors that might be created during runtime.

The would be disabled in the production environment.

Lastly, we need to require the react-hot-loader patch into our entry point file:

require('react-hot-loader/patch');

We require this because it’s responsible for patching the code at low-level processing.

Testing React Hot Loader

Let’s test our application to see if the state would be preserved on updates now, we can accomplish this by saving the updates we just made and running the application:

npm start

We can click on the button to increase the number variable to a number like 36:

Now, lets make a quick edit to the code and save it to see if the state persists:

import React, { Component } from 'react'; import logo from './logo.svg'; import './App.css'; class App extends Component { constructor(props){ super(props); this.state = { number : 0 } } render() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1 className="App-title">Welcome to React</h1> </header> <p className="App-intro"> Does the state persist now? The value is {this.state.number} </p> <button onClick={()=>this.setState({number : this.state.number + 1})}>+</button> </div> ); } } export default App;

This update causes the browser window to update to this:

Awesome! The state persisted despite the change we made to the document, this means that our react-hot-loader works perfectly and handles module reloading for us.

Conclusion

In this tutorial, we have gone from understanding why hot loading is important to specify the difference between a hot reload and a live reload. We have also seen how to quickly and easily setup a React application for hot reload using the react-hot-loader plugin so that the value of all states present in the application can be persisted regardless of the updates made. The final code of this article is available here on GitHub.

Full visibility into production React apps Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more. The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores. Modernize how you debug your React apps — start monitoring for free.