Tweak React components in real time ⚛️⚡️
Watch Dan Abramov's talk on Hot Reloading with Time Travel.
npm install react-hot-loader@next
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.
- Add
react-hot-loader/babel
to your.babelrc
:
// .babelrc
{
"plugins": ["react-hot-loader/babel"]
}
Note: use
.compilerc
in case of Electron
- Mark your root component as hot-exported:
// ./containers/App.js
import React from 'react'
import { hot } from 'react-hot-loader'
const App = () => <div>Hello World!</div>
export default hot(module)(App)
Do not use hot
if you are using parcel bundler. It was designed for webpack.
Hot
accepts only React Component (Stateful or Stateless), resulting the HotExported
variant of it.
The hot
function will setup current module to self-accept itself on reload, and will ignore all the changes, made for non-React components.
You may mark as much modules as you want. But HotExportedComponent
should be the only used export of a hot-module.
Note: Please note how often we have used
exported
keyword.hot
is for exports.
Note: does nothing in production mode, just passes App through.
webpack-dev-server --hot
Migrating from create-react-app
- Run
npm run eject
- Install React Hot Loader (
npm install --save-dev react-hot-loader
) - In
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'],
},
}
- Mark your App (
src/index.js
) as hot-exported:
// ./containers/App.js
import React from 'react'
import { hot } from 'react-hot-loader'
const App = () => <div>Hello World!</div>
export default hot(module)(App)
Migrating from create-react-app without ejecting
Users reports, that it is possible to use react-app-rewire-hot-loader to setup React-hot-loader without ejecting. Follow these code examples to repeat the approach.
When using TypeScript, Babel is not required, but RHL will not work without it. Just add babel-loader into your webpack configuration, with RHL-only config.
{
test: /\.tsx?$/,
use: [
{
loader: 'babel-loader',
options: {
babelrc: true,
plugins: ['react-hot-loader/babel'],
},
},
'ts-loader', // (or awesome-typescript-loader)
],
}
Parcel's HRM is a bit different.
- Do not use
hot
(v4) to make Components hot-reloadable. - Use
AppContainer
+module.hot.accept
(v3), follow the version 3 guide lines.
Do the same for any other bundler or framework. hot
is not a silver bullet. Sometimes it may break the stuff.
If something is not working (absolutely) - remove the hot
.
To enable HRM on webpack, just enable it
enableLiveReload({ strategy: 'react-hmr' })
Example - https://github.com/rllola/hmr-example-issue-2/blob/master/src/index.js
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 in the end of each module so you might not need source maps at all.
React Native supports hot reloading natively as of version 0.22.
Using React Hot Loader with React Native can cause unexpected issues (see #824) and is not recommended.
As long most of modern react-component-loader
(loadable-components,
react-loadable, and so on)
does not, and should not support RHL, just mark export of the imported component as
hotExported
.
Example using loadable-components:
// AsyncHello.js
import loadable from 'loadable-components'
const AsyncHello = loadable(() => import('./Hello.js'))
// Hello.js
import { hot } from 'react-hot-loader'
const Hello = () => 'Hello'
export default hot(module)(Hello) // <-- the only change to do
Because React Hot Loader creates proxied versions of your components, comparing reference types of elements won't work:
const element = <Component />
console.log(element.type === Component) // false
React Hot Loader exposes a function areComponentsEqual
to make it possible:
import { areComponentsEqual } from 'react-hot-loader'
const element = <Component />
areComponentsEqual(element.type, Component) // true
Webpack ExtractTextPlugin is not compatible with these two plugins. The solution is simple, disable them in development:
// Example for ExtractTextPlugin
new ExtractTextPlugin({
filename: 'styles/[name].[contenthash].css',
disable: NODE_ENV !== 'production',
})
Mark a component as hot.
import { hot } from 'react-hot-loader'
const App = () => 'Hello World!'
export default hot(module)(App)
Mark application as hot reloadable. Prefer using hot
helper.
import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import App from './containers/App'
const render = Component => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.getElementById('root'),
)
}
render(App)
// Webpack Hot Module Replacement API
if (module.hot) {
module.hot.accept('./containers/App', () => {
// if you are using harmony modules ({modules:false})
render(App)
// in all other cases - re-require App manually
render(require('./containers/App'))
})
}
Test if two components have the same type.
import { areComponentsEqual } from 'react-hot-loader'
import Component1 from './Component1'
import Component2 from './Component2'
areComponentsEqual(Component1, Component2) // true or false
Set a new configuration for React Hot Loader.
Available options are:
logLevel
: specify log level, default to"error"
, available values are:['debug', 'log', 'warn', 'error']
import { setConfig } from 'react-hot-loader'
setConfig({ logLevel: 'debug' })
Prior v4 the right way to setup React Hot Loader was to wrap your Application
with AppContainer
, set setup module acceptance by yourself. This approach is
still valid but only for advanced use cases, prefer using hot
helper.
React Hot Loader v3:
// App.js
import React from 'react'
const App = () => <div>Hello world!</div>
export default App
// main.js
import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import App from './containers/App'
const render = Component => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.getElementById('root'),
)
}
render(App)
// Webpack Hot Module Replacement API
if (module.hot) {
module.hot.accept('./containers/App', () => {
// if you are using harmony modules ({modules:false})
render(App)
// in all other cases - re-require App manually
render(require('./containers/App'))
})
}
React Hot Loader v4:
// App.js
import React from 'react'
import { hot } from 'react-hot-loader'
const App = () => <div>Hello world!</div>
export default hot(module)(App)
// main.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './containers/App'
ReactDOM.render(<App />, document.getElementById('root'))
Code is automatically patched, you can safely remove react-hot-loader/patch
from your Webpack config.
React supports error handling out of the box since v16 using componentDidCatch
. You can create your own Error Boundary and install it after hot
has been applied:
import React from 'react'
import { hot } from 'react-hot-loader'
import ErrorBoundary from './ErrorBoundary'
const App = () => (
<ErrorBoundary>
<div>Hello world!</div>
</ErrorBoundary>
)
export default hot(module)(App)
On code replace you are replacing the old code by a new one. You should not use
the old code, as thus allow RHL to safely modify it. See
react-stand-in
for more details.
There is no way to hot-update constructor code, as result even new components
will be born as the first ones, and then grow into the last ones. See
react-stand-in
for more details.
If it doesn't work, in 99% cases it's a configuration issue. A missing option, a wrong path or port. Webpack is very strict about configuration, and the best way to find out what's wrong is to compare your project to an already working setup, check out examples, bit by bit.
If something doesn't work, in 99% cases it's an issue with your code - Component doesn't got registered, due to HOC or Decorator around it, which making it invisible to Babel plugin, or Webpack loader.
We're also gathering Troubleshooting Recipes so send a PR if you have a lesson to share!
Debug mode adds additional warnings and can tells you why React Hot Loader is not working properly in your application.
import { setConfig } from 'react-hot-loader'
setConfig({ logLevel: 'debug' })
MIT