React Fast Refresh — The New React Hot Reloader

A Comprehensive Guide to Using React Fast Refresh

By Michael Chang

February 2nd, 2021

image

My Journey

While building a demo based off of Create React App for a medium article I noticed something unexpected— as I was editing the source code, my app would update but my state would be maintained. I was expecting my state to be reset like I had seem a million times working on other projects. I was confused and thought my app didn’t actually hot reload properly. But as I dug around more, I found out that this was an exciting new feature.

React Fast Refresh

This new functionality that I experienced is React Fast Refresh. It is the latest iteration of React hot reloading. When editing a React component, React Fast Refresh will efficiently only update and re-render that component. This leads to significantly faster hot reload times. In addition, React Fast Refresh will preserve component state during re-renders so you won’t need to manually create the same scenario again. These “fast” and painless re-renders create a superior developer experience, making the feedback loop between change and result significantly more efficient.

Create React App

Starting from 4.x, Create React App enables React Fast Refresh by default. If your project is built off of Create React App, all you need to do is upgrade.

Custom Webpack

If your project uses a custom Webpack configuration instead of Create React App, it’s still very simple to enable React Fast Refresh. First, install the react-refresh and @pmmmwh/react-refresh-webpack-plugin libraries. react-refresh contains the basic tooling needed support React Fast Refresh’s hot reloading andreact-refresh-webpack-plugin is the Webpack plugin needed to enable react-refresh.

Then, add the react-refresh/babel Babel plugin to the Babel configuration file

// babel.config.js

module.exports = function babel(api) {
  const BABEL_ENV = api.env();
  const presets = [...];
  const plugins = [...];
  if (BABEL_ENV === 'development') {
    plugins.push('react-refresh/babel');
  }
  return {
    presets,
    plugins,
  };
};

and add the react-refresh-webpack-plugin plugin to the Webpack configuration file.

// webpack.config.js

const ReactRefreshWebpackPlugin = require('[@pmmmwh/react-refresh-webpack-plu](http://twitter.com/pmmmwh/react-refresh-webpack-plu)gin');

module.exports = {
  ...
  plugins: [
    new ReactRefreshWebpackPlugin(),
  ],
};

Alternatively, you can specify the babel plugin directly in the Webpack configuration instead of the Babel configuration file.

// webpack.config.js

const ReactRefreshWebpackPlugin = require('[@pmmmwh/react-refresh-webpack-plu](http://twitter.com/pmmmwh/react-refresh-webpack-plu)gin');

module.exports = {
  ...
  plugins: [
    new ReactRefreshWebpackPlugin(),
  ],
  module: {
    rules: [
      {
        test: /\.[jt]sx?$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          plugins: ['react-refresh/babel'],
        },
      },
    ],
  },
};

And that’s it — you should now have the latest and greatest hot reloader React has to offer enabled for your project!

Disabling

The preservation of state is great but there may be occasional cases where you don’t want to preserve state. React Fast Refresh supports this with the // @refresh reset comment. If a component is edited and this comment is present somewhere in the file, React Fast Refresh will force the component to be remounted, which will reset the component state.

If you find yourself constantly adding this comment or face some of the limitations discussed below, you may want to take the drastic approach and not use React Fast Refresh all. Create React App provides the FAST_REFRESH flag to disable it and use the old hot reloader. This can be done by running FAST_REFRESH=false npm start or adding FAST_REFRESH=false to the .env file. If you are using your own custom Webpack, simply remove the configuration changes mentioned above.

Limitations

Unfortunately, React Fast Refresh does have some limitations. If React Fast Refresh cannot determine which React components to update, it will do the safe thing and fall back to doing a full reload. This case can arise if you use un-named / anonymous and non-PascalCased React components because React Fast Refresh cannot statically determine if the code is React-related.

A full reload will also occur if you edit files that eventually lead root even if some code in the file are React related. React Fast Refresh cannot guarantee that the non-React-related content can be hot reloaded so it assumes it cannot.

In addition, React Fast Refresh’s state preservation does not work for class components — it only works with function components and hooks. Previous iterations of hot reloading worked for class components but did so in an unsafe way that could potentially lead to incorrect unexpected behavior. React Fast Refresh focuses on safety so it currently does not support class components.

Prerelease

At the time of this writing, that react-refresh and @pmmmwh/react-refresh-webpack-plugin are both pre-v1 release so there may be issues. Having said that, the Facebook team has enough confidence in these libraries to enable it by default it in Create React App 4.x. For me, that alone is enough to begin using it in my projects.

Final Thoughts

Having learned about React Fast Refresh, I have since integrated it in all my projects. It has made development far more efficient by smartly hot reloading only when necessary and maintaining application state. Now, I get my changes reflected in the UI faster, and it automatically is in the same state as before. While there are some limitations, I have not faced any fundamental problems, and worse case, it behaves exactly like the previous generation hot reloader. React Fast Refresh absolutely is a worthy successor to existing React hot reloading.

Resources



Continue Learning