[![Build Status][build-badge]][build] [![version][version-badge]][package] [![Code Coverage][coverage-badge]][coverage] [![MIT License][license-badge]][license]
[![PRs Welcome][prs-badge]][prs] [![Chat][chat-badge]][chat] ![Backers on Open Collective][oc-backer-badge] ![Sponsors on Open Collective][oc-sponsor-badge]
[![Watch on GitHub][github-watch-badge]][github-watch] [![Star on GitHub][github-star-badge]][github-star]
Tweak React components in real time ⚛️⚡️
Watch Dan Abramov's talk on Hot Reloading with Time Travel.
React-Hot-Loader has been your friendly neighbour, living outside of React. But it has been limiting its powers and causing not the greatest experience. It's time to make a next step.
React-Hot-Loader is expected to be replaced by React Fast Refresh. Please remove React-Hot-Loader if Fast Refresh is currently supported on your environment.
React Native - supports Fast Refresh since 0.61.parcel 2 - supports Fast Refresh since alpha 3.webpack - supports Fast Refresh using a plugin.other bundler - no support yet, use React-Hot-Loadercreate-react-app - supports Fast Refresh with FAST_REFRESH env since 4.next.js - supports Fast Refresh since 9.4npm install react-hot-loader
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.
react-hot-loader/babel to your .babelrc:// .babelrc
{
"plugins": ["react-hot-loader/babel"]
}
// App.js
import { hot } from 'react-hot-loader/root';
const App = () =>
Hello World!
;
export default hot(App);
Make sure react-hot-loader is required before react and react-dom:
or import 'react-hot-loader' in your main file (before React)
or prepend your webpack entry point with react-hot-loader/patch, for example:
js
// webpack.config.js
module.exports = {
entry: ['react-hot-loader/patch', './src'],
// ...
};
If you need hooks support, use @hot-loader/react-dom
Hooks would be auto updated on HMR if they should be. There is only one condition for it - a non zero dependencies list.
❄️ useState(initialState); // will never updated (preserve state)
❄️ useEffect(effect); // no need to update, updated on every render
❄️ useEffect(effect, []); // "on mount" hook. "Not changing the past"
🔥 useEffect(effect, [anyDep]); // would be updated
🔥 useEffect(effect, ["hot"]); // the simplest way to make hook reloadable
Plus
reloadHooksOnBodyChange option.reloadLifeCycleHooks option to true.To disable hooks reloading - set configuration option:
import { setConfig } from 'react-hot-loader';
setConfig({
reloadHooks: false,
});
With this option set all useEffects, useCallbacks and useMemo would be updated on Hot Module Replacement.
Hooks would be reset if their order changes. Adding, removing or moving around would cause a local tree remount.
Babel plugin is required for this operation. Without it changing hook order would throw an error which would be propagated till the nearest class-based component.
@hot-loader/react-dom@hot-loader/react-dom replaces the "react-dom" package of the same version, but with additional patches to support hot reloading.
There are 2 ways to install it:
@hot-loader/react-dom would be installed instead of react-domyarn add react-dom@npm:@hot-loader/react-dom
yarn add @hot-loader/react-dom
// webpack.config.js
module.exports = {
// ...
resolve: {
alias: {
'react-dom': '@hot-loader/react-dom',
},
},
};
Note: There is also an old version of hot, used prior to version 4.5.4. Please use the new one,
as it is much more resilient to js errors that you may make during development.
Meanwhile, not all the bundlers are compatible with new /root API, for example parcel is not.
React-Hot-Load will throw an error, asking you to use the old API, if such incompatibility would be detected.
It is almost the same, but you have to pass module inside hot.
import { hot } from 'react-hot-loader';
const App = () =>
Hello World!
;
export default hot(module)(App);
webpack-dev-server --hot
The webpack patch, hot, Babel plugin, @hot-loader/react-dom etc. are all safe to use in production; they leave a minimal footprint, so there is no need to complicate your configuration based on the environment. Using the Babel plugin in production is even recommended because it switches to cleanup mode.
Just ensure that the production mode has been properly set, both as an environment variable and in your bundler. E.g. with webpack you would build your code by running something like:
NODE_ENV=production webpack --mode production
NODE_ENV=production is needed for the Babel plugin, while --mode production uses webpack.DefinePlugin to set process.env.NODE_ENV inside the compiled code itself, which is used by hot and @hot-loader/react-dom.
Make sure to watch your bundle size when implementing react-hot-loader to ensure that you did it correctly.
componentWillUnmount or componentDidMount would be ignored for already created components.state.constructor. Unless an existing component is recreated, RHL would typically inject new data into that component, but there is no way to detect the actual change or the way it was applied, especially if the change was made to a function. This is because of the way React-Hot-Loader works - it knows what class functions are, not how they were created. See #1001 for details.npm run ejectnpm install --save-dev react-hot-loader)config/webpack.config.dev.js, add 'react-hot-loader/babel' to Babel
loader configuration. The loader should now look like: {
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'],
},
}
src/App.js) as hot-exported:// ./containers/App.js
import React from 'react';
import { hot } from 'react-hot-loader';
const App = () =>
Hello World!
;
export default hot(module)(App);
Users report, that it is possible to use react-app-rewire-hot-loader to setup React-hot-loader without ejecting.
As of version 4, React Hot Loader requires you to pass your code through Babel to transform it so that it can be hot-reloaded. This can be a pain point for TypeScript users, who usually do not need to integrate Babel as part of their build process.
Fortunately, it's simpler than it may seem! Babel will happily parse TypeScript syntax and can act as an alternative to the TypeScript compiler, so you can safely replace ts-loader or awesome-typescript-loader in your Webpack configuration with babel-loader. Babel won't typecheck your code, but you can use fork-ts-checker-webpack-plugin (and/or invoke tsc --noEmit) as part of your build process instead.
A sample configuration:
{
// ...you'll probably need to configure the usual Webpack fields like "mode" and "entry", too.
resolve: { extensions: [".ts", ".tsx", ".js", ".jsx"] },
module: {
rules: [
{
test: /\.(j|t)sx?$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
cacheDirectory: true,
babelrc: false,
presets: [
[
"@babel/preset-env",
{ targets: { browsers: "last 2 versions" } } // or whatever your project requires
],
"@babel/preset-typescript",
"@babel/preset-react"
],
plugins: [
// plugin-proposal-decorators is only needed if you're using experimental decorators in TypeScript
["@babel/plugin-proposal-decorators", { legacy: true }],
["@babel/plugin-proposal-class-properties", { loose: true }],
"react-hot-loader/babel"
]
}
}
}
]
},
plugins: [
new ForkTsCheckerWebpackPlugin()
]
};
For a full example configuration of TypeScript with React Hot Loader and newest beta version of Babel, check here.
As an alternative to this approach, it's possible to chain Webpack loaders so that your code passes through Babel and then TypeScript (or TypeScript and then Babel), but this approach is not recommended as it is more complex and may be significantly less performant. Read more discussion here.
Parcel supports Hot Module Reloading out of the box, just follow step 1 and 2 of Getting Started.
We also have a full example running Parcel + React Hot Loader.
You need something to mark your modules as hot in order to use React Hot Loader.
One way of doing this with Electron is to simply use webpack like any web-based project might do and the general guide above describes. See also this example Electron app.
A webpack-less way of doing it to use electron-compile (which is also used by electron-forge) - see this example. While it requires less configuration, something to keep in mind is that electron-compile's HMR will always reload all modules, regardless of what was actually edited.
If you use devtool: 'source-map' (or its equivalent), source maps will be
emitted to hide hot reloading code.
Source maps slow down your project. Use devtool: 'eval' for best build
performance.
Hot reloading code is just one line in the beginning and one line at the end of each module so you might not need source maps at all.
If you are using npm link or yarn link for development purposes, there is a chance you will get error Module not found: Error: Cannot resolve module 'react-hot-loader' or the linked package is not hot reloaded.
There are 2 ways to fix Module not found:
include in loader configuration to only opt-in your app's files to processing.{
resolve: {
alias: {
'react-hot-loader': path.resolve(path.join(__dirname, './node_modules/react-hot-loader')),
}
}
}
And to make your linked package to be hot reloaded, it will need to use the patched version of react and react-dom, if you're using webpack, add this options to the alias config
{
resolve: {
alias: {
'react-hot-loader': path.resolve(path.join(__dirname, './node_modules/react-hot-loader')),
// add these 2 lines below so linked package will reference the patched version of `react` and `react-dom`
'react': path.resolve(path.join(__dirname, './node_modules/react')),
'react-dom': path.resolve(path.join(__dirname, './node_modules/react-dom')),
// or point react-dom above to './node_modules/@hot-loader/react-dom' if you are using it
}
}
}
React-hot-loader should work out of the box with preact-compat, but, in case of pure preact, you will need
to configure it:
$ claude mcp add react-hot-loader \
-- python -m otcore.mcp_server <graph>