Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Tweak React components in real time. (Deprecated: use Fast Refresh instead.)

License

NotificationsYou must be signed in to change notification settings

gaearon/react-hot-loader

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build StatusversionCode CoverageMIT License

PRs WelcomeChatBackers on Open CollectiveSponsors on Open Collective

Watch on GitHubStar on GitHub

Tweak React components in real time ⚛️⚡️

WatchDan Abramov's talk on Hot Reloading with Time Travel.

Moving towards next step

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 byReact Fast Refresh. Please remove React-Hot-Loader if Fast Refresh is currently supported on your environment.

Install

npm install react-hot-loader

Note: You can safely install react-hot-loader as a regular dependency insteadof a dev dependency as it automatically ensures it is not executed inproduction and the footprint is minimal.

Getting started

  1. Addreact-hot-loader/babel to your.babelrc:
// .babelrc{"plugins":["react-hot-loader/babel"]}
  1. Mark your root component ashot-exported:
// App.jsimport{hot}from'react-hot-loader/root';constApp=()=><div>Hello World!</div>;exportdefaulthot(App);
  1. Make surereact-hot-loader is required beforereact andreact-dom:
  • orimport 'react-hot-loader' in your main file (before React)
  • or prepend your webpack entry point withreact-hot-loader/patch, for example:
    // webpack.config.jsmodule.exports={entry:['react-hot-loader/patch','./src'],// ...};
  1. If you need hooks support, use@hot-loader/react-dom

Hook support

Hooks would be auto updated on HMR if theyshould 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

  • any hook would be reloaded on a function body change. Enabled by default, controlled byreloadHooksOnBodyChange option.
  • you may configure RHL to reload any hook by settingreloadLifeCycleHooks option to true.

To disable hooks reloading - set configuration option:

import{setConfig}from'react-hot-loader';setConfig({reloadHooks:false,});

With this option setalluseEffects,useCallbacks anduseMemo would be updated on Hot Module Replacement.

Hooks reset

Hooks would be reset if their order changes. Adding, removing or moving around wouldcause a local tree remount.

Babel plugin is required for this operation. Without it changing hook order would throw an errorwhich 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:

  • Useyarn name resolution, so@hot-loader/react-dom would be installed instead ofreact-dom
yarn add react-dom@npm:@hot-loader/react-dom
yarn add @hot-loader/react-dom
// webpack.config.jsmodule.exports={// ...resolve:{alias:{'react-dom':'@hot-loader/react-dom',},},};

Old API

Note: There is also an old version ofhot, 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 exampleparcel 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 passmodule insidehot.

import{hot}from'react-hot-loader';constApp=()=><div>Hello World!</div>;exportdefaulthot(module)(App);
  1. Run webpack with Hot Module Replacement:
webpack-dev-server --hot

What about production?

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 useswebpack.DefinePlugin to setprocess.env.NODE_ENV inside the compiled code itself, which is used byhot and@hot-loader/react-dom.

Make sure to watch your bundle size when implementing react-hot-loader to ensure that you did it correctly.

Limitations

  • (that's the goal) React-Hot-Loader would not change the past, only update the present - no lifecycle event would be called on component update. As a result, any code changes made tocomponentWillUnmount orcomponentDidMount would be ignored for already created components.
  • (that's the goal) React-Hot-Loader would not update any object, including componentstate.
  • (1%) React-Hot-Loader may not apply some changes made to a component'sconstructor. Unless an existing component is recreated, RHL would typicallyinject 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.

Recipes

Migrating fromcreate-react-app

  1. Runnpm run eject
  2. Install React Hot Loader (npm install --save-dev react-hot-loader)
  3. Inconfig/webpack.config.dev.js, add'react-hot-loader/babel' to Babelloader 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'],},}
  1. Mark your App (src/App.js) ashot-exported:
// ./containers/App.jsimportReactfrom'react';import{hot}from'react-hot-loader';constApp=()=><div>Hello World!</div>;exportdefaulthot(module)(App);

Migrating fromcreate-react-app without ejecting

Usersreport, that it is possible to usereact-app-rewire-hot-loader to setup React-hot-loader without ejecting.

TypeScript

As of version 4, React Hot Loader requires you to pass your code throughBabel 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 replacets-loader orawesome-typescript-loader in your Webpack configuration withbabel-loader. Babel won't typecheck your code, but you can usefork-ts-checker-webpack-plugin (and/or invoketsc --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:[newForkTsCheckerWebpackPlugin()]};

For a full example configuration of TypeScript with React Hot Loader and newest beta version of Babel, checkhere.

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 morediscussion here.

Parcel

Parcel supports Hot Module Reloading out of the box, just follow step 1 and 2 ofGetting Started.

We also have afull example running Parcel + React Hot Loader.

Electron

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 alsothis example Electron app.

A webpack-less way of doing it to useelectron-compile (which is also used byelectron-forge) - seethis example. While it requires less configuration, something to keep in mind is thatelectron-compile's HMR will always reload all modules, regardless of what was actually edited.

Source Maps

If you usedevtool: 'source-map' (or its equivalent), source maps will beemitted to hide hot reloading code.

Source maps slow down your project. Usedevtool: 'eval' for best buildperformance.

Hot reloading code is just one line in the beginning and one line at the end ofeach module so you might not need source maps at all.

Linking

If you are usingnpm link oryarn link for development purposes, there is a chance you will get errorModule not found: Error: Cannot resolve module 'react-hot-loader' or the linked package is not hot reloaded.

There are 2 ways to fixModule not found:

  • Useinclude in loader configuration to only opt-in your app's files to processing.
  • Alternatively if you are using webpack, override the module resolution in your config:
{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 ofreact andreact-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}}}

Preact

React-hot-loader should work out of the box withpreact-compat, but, in case of pure preact, you will needto configure it:

  • create configuration file (setupHotLoader.js)
importreactHotLoaderfrom'react-hot-loader';importpreactfrom'preact';reactHotLoader.preact(preact);
  • dont forget to import it

Preact limitations

  • HOCs and Decorators as not supported yet. For Preact React-Hot-Loader v4 behave as v3.

React Native

React Nativesupports hot reloading nativelyas of version 0.22.

Using React Hot Loader with React Native can cause unexpected issues (see #824) and is not recommended.

Webpack plugin

We recommend using thebabel plugin, but there are some situations where you are unable to. If so, try thewebpack plugin /webpack-loader (as seen in v3).

Remember - thewebpack plugin isnot compatible with class-based components. Thebabel pluginwill inject special methods to every class, to makeclass members (like onClick) hot-updatable, while thewebpack plugin would leave classes as is, without anyinstrumentation.

classMyComponentextendsReact.Component{onClick=()=>this.setState();// COULD NOT UPDATEvariable=1;// this is okrender(){}// this is ok}

Butwebpack-loader could help with TypeScript orspreading "cold API"to all node_modules.

It is possible to enable this loader for all the files, but if you usebabel plugin, you need to enable this loader forreact-dom only. Place it after babel-loader, if babel-loader is present.

// webpack.config.jsmodule.exports={module:{rules:[// would only land a "hot-patch" to react-dom{test:/\.js$/,include:/node_modules\/react-dom/,use:['react-hot-loader/webpack'],},],},};

Webpack plugin will also land a "hot" patch to react-dom, making React-Hot-Loader more compliant tothe principles.

If you are not usingbabel plugin you might need to applywebpack-loader to all the files.

{test:/\.jsx?$/,include:/node_modules/,use:['react-hot-loader/webpack']},

Code Splitting

If you want to use Code Splitting + React Hot Loader, the simplest solution is to pick a library compatible with this one:

If you use a not-yet-friendly library, likereact-async-component,or are having problems with hot reloading failing to reload code-split components,you can manually mark the components below the code-split boundaries.

// AsyncHello.jsimport{asyncComponent}from'react-async-component';// asyncComponent could not `hot-reload` itself.constAsyncHello=asyncComponent({resolve:()=>import('./Hello'),});exportdefaultAsyncHello;

Note thatHello is the component at the root of this particularcode-split chunk.

// Hello.jsimport{hot}from'react-hot-loader/root';constHello=()=>'Hello';exportdefaulthot(Hello);// <-- module will reload itself

Wrapping this root component withhot() will ensure that it is hot reloaded correctly.

Out-of-bound warning

You may see the following warning when code-split components are updated:

React-Hot-Loader: some components were updated out-of-bound. Updating your app to reconcile the changes.

This is because the hot reloading of code-split components happens asynchronously. If you had anApp.js that implementedtheAsyncHello component above and you modifiedAsyncHello, it would be bundled and reloaded at the same time asApp.js. However, the core hot reloading logic is synchronous, meaning that it's possible for the hot reload to run beforethe updates to the split component have landed.

In this case, RHL uses a specialtail update detection logic, where it notes that an an update to a split componenthas happened after the core hot reloading logic has already finished, and it triggers another update cycle to ensurethat all changes are applied.

The warning is informational - it is a notice that this tail update logic is triggered, and does not indicate a problemin the configuration or useage ofreact-hot-loader.

If the tail update detection is not something you want or need, you can disable this behavior by settingsetConfig({ trackTailUpdates:false }).

Checking Elementtypes

Because React Hot Loader creates proxied versions of your components, comparingreference types of elements won't work:

constelement=<Component/>;console.log(element.type===Component);// false

React Hot Loader exposes a functionareComponentsEqual to make it possible:

import{areComponentsEqual}from'react-hot-loader';constelement=<Component/>;areComponentsEqual(element.type,Component);// true

Another way - compare "rendered" element type

constelement=<Component/>;console.log(element.type===<Component/>.type);// true// better - precache rendered typeconstelement=<Component/>;constComponentType=<Component/>.type;console.log(element.type===ComponentType);// true

But you might have to provide all required props. Seeoriginal issue.This is most reliable way to compare components, but it will not work with required props.

Another way - compare Component name.

Not all components have a name.In production displayName could not exists.

constelement=<Component/>;console.log(element.displayName==='Component');// true

This is something we did not solve yet. Cold API could help keep original types.

Webpack ExtractTextPlugin

webpack ExtractTextPlugin is not compatible with React Hot Loader. Please disable it in development:

newExtractTextPlugin({filename:'styles/[name].[contenthash].css',disable:NODE_ENV!=='production',});

Disabling a type change (❄️)

It is possible to disable React-Hot-Loader for a specific component, especially toenable common way to type comparison.See #991 for the idea behind ⛄️, and #304 about "type comparison" problem.

import{cold}from'react-hot-loader';cold(SomeComponent)// this component will ignored by React-Hot-Loader<SomeComponent/>.type===SomeComponent// true

If you will updatecold component React-Hot-Loader will complain (on error level), and thenReact will cold-replace Component with a internal state lose.

Reach-Hot-Loader: cold element got updated

Disabling a type change for all node_modules

You maycold all components from node_modules. This will not work for HOC(like Redux) or dynamically created Components, but might help in most of situations, when type changesare not welcomed, and modules are not expected to change.

import{setConfig,cold}from'react-hot-loader';setConfig({onComponentRegister:(type,name,file)=>file.indexOf('node_modules')>0&&cold(type),// some components are not visible as top level variables,// thus its not known where they were createdonComponentCreate:(type,name)=>name.indexOf('styled')>0&&cold(type),});

! To be able to "cold" components from 'node_modules' you have to apply babel to node_modules, while thisfolder is usually excluded.You may add one more babel-loader, with only one React-Hot-Loader plugin inside to solve this.Consider using webpack-loader for this.

React-Hooks

React hooks are notreally supported by React-Hot-Loader. Mostly due to our internalprocesses of re-rendering React Tree, which is required to reconcile an updated applicationbefore React will try to rerender it, and fail to do that, obviously.

  • hooksshould work for versions 4.6.0 and above (pureSFC is enabled by default).
  • hooks will produceerrors on every hot-update without patches toreact-dom.
  • hooksmay loss the state without patches toreact-dom.
  • hooks does not support adding new hooks on the fly
  • change in hooks for a mounted components will cause a runtime exception, and aretry button (at the nearest class component) will be shown.Pressing aretry button will basically remount tree branch.

To mitigate any hook-related issues (and disable their hot-reloadability) -cold them.

  • cold components using hooks.
import{setConfig,cold}from'react-hot-loader';setConfig({onComponentCreate:(type,name)=>(String(type).indexOf('useState')>0||String(type).indexOf('useEffect')>0)&&cold(type),});

API

hot(Component, options)

Mark a component as hot.

Babel plugin

Right now babel plugin has only one option, enabled by default.

  • safetyNet - will help you properly setup ReactHotLoader.

You may disable it to get more control on the module execution order.

//.babelrc{"plugins":[["react-hot-loader/babel",{"safetyNet":false}]]}

Important

!! Usehot only for moduleexports, not for moduleimports.!!

import{hot}from'react-hot-loader/root';constApp=()=>'Hello World!';exportdefaulthot(App);

Keep in mind - by importingreact-hot-loader/root you are setting up a boundary for update event propagation.

The higher(in module hierarchy) you have it - the more stuff would be updated on Hot Module Replacement.

To make RHL more reliable and safe, please placehotbelow (ie somewhere inimported modules):

  • react-dom
  • redux store creation
  • any data, you want to preserve between updates
  • big libraries

You may(but it's not required) placehot to the every route/page/feature/lazy chunk, thus make updates more scoped.

You don't need to wrap every component withhot, application works fine with a single one.

(old)hot(module, options)(Component, options)

Mark a component as hot. The "new" hot is just hidding the first part -hot(module), giving youonly the second(App). The "new" hot is using old API.

import{hot}from'react-hot-loader';constApp=()=>'Hello World!';exportdefaulthot(module)(App);

AppContainer

Mark application as hot reloadable. (Prefer usinghot helper, see below for migration details).

This low-level approach lets you make **hot **imports__, not exports.

importReactfrom'react';importReactDOMfrom'react-dom';import{AppContainer}from'react-hot-loader';importAppfrom'./containers/App';constrender=Component=>{ReactDOM.render(<AppContainer><Component/></AppContainer>,document.getElementById('root'),);};render(App);// webpack Hot Module Replacement APIif(module.hot){// keep in mind - here you are configuring HMR to accept CHILDREN MODULE// while `hot` would configure HMR for the CURRENT modulemodule.hot.accept('./containers/App',()=>{// if you are using harmony modules ({modules:false})render(App);// in all other cases - re-require App manuallyrender(require('./containers/App'));});}

areComponentsEqual(Component1, Component2)

Test if two components have the same type.

import{areComponentsEqual}from'react-hot-loader';importComponent1from'./Component1';importComponent2from'./Component2';areComponentsEqual(Component1,Component2);// true or false

setConfig(config)

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']
  • pureSFC: enable Stateless Functional Component. If disabled they will be converted to React Components.Default value: false.
  • ignoreSFC: skip "patch" for SFC. "Hot loading" could still work, with webpack-patch present
  • pureRender: do not amendrender method of any component.
  • for the rest seeindex.d.ts.
// rhlConfig.jsimport{setConfig}from'react-hot-loader';setConfig({logLevel:'debug'});

It is important to set configuration before any other action will take a place

// index.jsimport'./rhlConfig'// <-- extract configuration to a separate file, and import it in the begginingimportReactfrom'react'....

Migrating from v3

AppContainer vs hot

Prior v4 the right way to setup React Hot Loader was to wrap your ApplicationwithAppContainer, set setup module acceptance by yourself. This approach isstill valid but only for advanced use cases, prefer usinghot helper.

React Hot Loader v3:

// App.jsimportReactfrom'react';constApp=()=><div>Hello world!</div>;exportdefaultApp;
// main.jsimportReactfrom'react';importReactDOMfrom'react-dom';import{AppContainer}from'react-hot-loader';importAppfrom'./containers/App';constrender=Component=>{ReactDOM.render(<AppContainer><Component/></AppContainer>,document.getElementById('root'),);};render(App);// webpack Hot Module Replacement APIif(module.hot){module.hot.accept('./containers/App',()=>{// if you are using harmony modules ({modules:false})render(App);// in all other cases - re-require App manuallyrender(require('./containers/App'));});}

React Hot Loader v4:

// App.jsimportReactfrom'react';import{hot}from'react-hot-loader';constApp=()=><div>Hello world!</div>;exportdefaulthot(module)(App);
// main.jsimportReactfrom'react';importReactDOMfrom'react-dom';importAppfrom'./containers/App';ReactDOM.render(<App/>,document.getElementById('root'));

Patch is optional

Since 4.0 till 4.8

Code is automatically patched, you can safely removereact-hot-loader/patch from your webpack config,if react-hot-loader is required before React in any other way.

Error Boundary is inside every component

Since 4.5.4

On Hot Module Update we will injectcomponentDidCatch and aspecialrenderto every Class-based component you have, makingError Boundaries more local.

After update we will remove all sugar, keeping only Boundaries you've created.

You can provide your ownerrorReporter, viasetConfig({errorReporter}) or opt-out fromroot ErrorBoundaries settingerrorBoundary={false} prop onAppContainer orhot.However - this option affects only SFC behavior, and any ClassComponent would boundary itself.

import{setConfig}from'react-hot-loader';importErrorBoundaryfrom'./ErrorBoundary';// ErrorBoundary will be given error and errorInfo prop.setConfig({errorReporter:ErrorBoundary});

IferrorReporter is not set - full screen error overlay would be shown.

Setting global Error Reporter

Global Error Reporter would, created a fixed overlay on top the page,would be used to display errors, not handled byerrorReporter, andany HMR error.

You may change, or disable this global error overlay

// to disablesetConfig({ErrorOverlay:()=>null});// to changesetConfig({ErrorOverlay:MyErrorOverlay});

The UX of existing overlay is a subject to change, and we are open to any proposals.

Known limitations and side effects

Note abouthot

hot accepts only React Component (Stateful or Stateless), resulting theHotExported variant of it.Thehot function will setup current module toself-accept itself on reload, and willignore all the changes, made for non-React components.You may mark as many modules as you want. ButHotExportedComponentshould be the only used export of ahot-module.

Note: Please note how often we have usedexported keyword.hot is for exports.

Note: Does nothing in production mode, just passes App through.

New Components keep executing the old code

There is no way to hot-update constructor code, as result even new componentswill be born as the first ones, and then grow into the last ones. As of today, this issue cannot be solved.

Troubleshooting

If it doesn't work, in 99% of cases it's a configuration issue. A missing option, awrong path or port. webpack is very strict about configuration, and the best wayto find out what's wrong is to compare your project to an already working setup,check outexamples,bit by bit.

If something doesn't work, in 99% of cases it's an issue with your code. The Componentdidn't get registered, due to HOC or Decorator around it, which is making itinvisible to the Babel plugin or webpack loader.

We're also gatheringTroubleshooting Recipesso send a PR if you have a lesson to share!

Switch into debug mode

Debug mode adds additional warnings and can tells you why React Hot Loader isnot working properly in your application.

import{setConfig}from'react-hot-loader';setConfig({logLevel:'debug'});

Contributors

This project exists thanks to all the people who contribute.Contribute.contributors

Backers

Thank you to all our backers! 🙏Become a backerbackers

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website.Become a sponsor

License

MIT

About

Tweak React components in real time. (Deprecated: use Fast Refresh instead.)

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors240


[8]ページ先頭

©2009-2025 Movatter.jp