React-hot-loader: Hot reloading fails for components which have a class property render method

Created on 2 Apr 2018  ·  11Comments  ·  Source: gaearon/react-hot-loader

If you are reporting a bug or having an issue setting up React Hot Loader, please fill in below. For feature requests, feel free to remove this template entirely.

Description

What you are reporting:

Hot reloading fails for components which have a class property render method.

import React from 'react';

export default class Example extends React.PureComponent {
  render = () => 'Hello, example!';
}

Expected behavior

What you think should happen:

Hot reloading should work correctly for components which have a class property render method.

Actual behavior

What actually happens:

A debug message is logged in the browser console (with logLevel set to debug) and the component does not reload.

React-hot-loader: reconcilation failed due to error 
TypeError: CurrentComponent.prototype.render is undefined
Stack trace:
hotComponentRender@http://localhost:3000/static/js/bundle.js:29410:7
render@http://localhost:3000/static/js/bundle.js:29859:43
hotReplacementRender@http://localhost:3000/static/js/bundle.js:29965:56
next@http://localhost:3000/static/js/bundle.js:29986:7
hotReplacementRender/<@http://localhost:3000/static/js/bundle.js:30016:9
hotReplacementRender@http://localhost:3000/static/js/bundle.js:29970:3
next@http://localhost:3000/static/js/bundle.js:29986:7
hotReplacementRender/<@http://localhost:3000/static/js/bundle.js:30016:9
hotReplacementRender@http://localhost:3000/static/js/bundle.js:29970:3
next@http://localhost:3000/static/js/bundle.js:29986:7
hotReplacementRender/<@http://localhost:3000/static/js/bundle.js:30016:9
hotReplacementRender@http://localhost:3000/static/js/bundle.js:29970:3
hotReplacementRender$1@http://localhost:3000/static/js/bundle.js:30037:5
reconcileHotReplacement@http://localhost:3000/static/js/bundle.js:30046:10
renderReconciler@http://localhost:3000/static/js/bundle.js:30060:7
asyncReconciledRender@http://localhost:3000/static/js/bundle.js:30068:3
proxiedRender@http://localhost:3000/static/js/bundle.js:29417:5
finishClassComponent@http://localhost:3000/static/js/bundle.js:14844:24
updateClassComponent@http://localhost:3000/static/js/bundle.js:14812:12
beginWork@http://localhost:3000/static/js/bundle.js:15433:16
performUnitOfWork@http://localhost:3000/static/js/bundle.js:18245:16
workLoop@http://localhost:3000/static/js/bundle.js:18268:26
renderRoot@http://localhost:3000/static/js/bundle.js:18299:9
performWorkOnRoot@http://localhost:3000/static/js/bundle.js:18855:24
performWork@http://localhost:3000/static/js/bundle.js:18776:9
performSyncWork@http://localhost:3000/static/js/bundle.js:18753:5
requestWork@http://localhost:3000/static/js/bundle.js:18653:7
scheduleWorkImpl@http://localhost:3000/static/js/bundle.js:18528:13
scheduleWork@http://localhost:3000/static/js/bundle.js:18488:12
enqueueForceUpdate@http://localhost:3000/static/js/bundle.js:13165:7
./node_modules/react/cjs/react.development.js/Component.prototype.forceUpdate@http://localhost:3000/static/js/bundle.js:30618:3
updateInstances/module.updateTimeout</<@http://localhost:3000/static/js/bundle.js:30229:16
updateInstances/module.updateTimeout<@http://localhost:3000/static/js/bundle.js:30228:7
hotComponentRender@http://localhost:3000/static/js/bundle.js:54668:7
render@http://localhost:3000/static/js/bundle.js:55117:43
hotReplacementRender@http://localhost:3000/static/js/bundle.js:55223:56
next@http://localhost:3000/static/js/bundle.js:55244:7
hotReplacementRender/<@http://localhost:3000/static/js/bundle.js:55274:9
hotReplacementRender@http://localhost:3000/static/js/bundle.js:55228:3
next@http://localhost:3000/static/js/bundle.js:55244:7
hotReplacementRender/<@http://localhost:3000/static/js/bundle.js:55274:9
hotReplacementRender@http://localhost:3000/static/js/bundle.js:55228:3
next@http://localhost:3000/static/js/bundle.js:55244:7
hotReplacementRender/<@http://localhost:3000/static/js/bundle.js:55274:9
hotReplacementRender@http://localhost:3000/static/js/bundle.js:55228:3
next@http://localhost:3000/static/js/bundle.js:55244:7
hotReplacementRender/<@http://localhost:3000/static/js/bundle.js:55274:9
hotReplacementRender@http://localhost:3000/static/js/bundle.js:55228:3
next@http://localhost:3000/static/js/bundle.js:55244:7
hotReplacementRender/<@http://localhost:3000/static/js/bundle.js:55274:9
hotReplacementRender@http://localhost:3000/static/js/bundle.js:55228:3
hotReplacementRender$1@http://localhost:3000/static/js/bundle.js:55295:5
reconcileHotReplacement@http://localhost:3000/static/js/bundle.js:55304:10
renderReconciler@http://localhost:3000/static/js/bundle.js:55318:7
asyncReconciledRender@http://localhost:3000/static/js/bundle.js:55326:3
proxiedRender@http://localhost:3000/static/js/bundle.js:54675:5
finishClassComponent@http://localhost:3000/static/js/bundle.js:40102:24
updateClassComponent@http://localhost:3000/static/js/bundle.js:40070:12
beginWork@http://localhost:3000/static/js/bundle.js:40691:16
performUnitOfWork@http://localhost:3000/static/js/bundle.js:43503:16
workLoop@http://localhost:3000/static/js/bundle.js:43526:26
renderRoot@http://localhost:3000/static/js/bundle.js:43557:9
performWorkOnRoot@http://localhost:3000/static/js/bundle.js:44113:24
performWork@http://localhost:3000/static/js/bundle.js:44034:9
performSyncWork@http://localhost:3000/static/js/bundle.js:44011:5
requestWork@http://localhost:3000/static/js/bundle.js:43911:7
scheduleWorkImpl@http://localhost:3000/static/js/bundle.js:43786:13
scheduleWork@http://localhost:3000/static/js/bundle.js:43746:12
enqueueForceUpdate@http://localhost:3000/static/js/bundle.js:38423:7
./node_modules/react/cjs/react.development.js/Component.prototype.forceUpdate@http://localhost:3000/static/js/bundle.js:58705:3
updateInstances/module.updateTimeout</<@http://localhost:3000/static/js/bundle.js:55487:16
updateInstances/module.updateTimeout<@http://localhost:3000/static/js/bundle.js:55486:7
react-hot-loader.development.js:88

Environment

React Hot Loader version: 4.0.1

Run these commands in the project folder and fill in their results:

  1. node -v: v8.10.0
  2. npm -v: v5.6.0

Then, specify:

  1. Operating system: Ubuntu 17.04
  2. Browser and version: Firefox 59.0.2 (64-bit)

Reproducible Demo

https://github.com/jackwilsdon/react-hot-loader-class-properties

Steps to reproduce

  1. Start the server with npm run start or yarn start.
  2. Visit the application in your browser and note it says "Hello, example!".
  3. Change src/components/Example.js to say something else.
  4. Note that the component does not re-render and that an error is logged in the console.

Most helpful comment

So the main thing here - there were no issues with the provided code. Only for the nested components, and even they possible were able to hot-reload themselves.
I had to spend some time to get red tests to fix them. Anyway - PR is opened.

All 11 comments

I did a bit of investigative work into this, and it seems that this is due to how class properties work and how we access the render method of a component on hot reload.

Babel converts class properties to look something like this;

function Example() {
  this.render = function() {
     return "Hello, example!";
  };
}

Which does not put the method on the prototype. The issue is that we try and call the render method on the prototype here;

https://github.com/gaearon/react-hot-loader/blob/10a320c9cb6c0c852737f9e1b6b57d177dfe4007/src/proxy/createClassProxy.js#L150-L158

I'm not sure if there is a solution to this or whether we should just add a warning about it, as it doesn't seem like you can re-bind the context of an arrow function.

Yeah, it is better to codemod this code, as long we could not distinguish a "local prop" render method and "render method we got from the prototype". Just because we are using render as a descriptor.
To many of them :)

I guess there's no solution for this then. Cheers :+1:

Sorry about it. Might be solved with #840

@jackwilsdon sorry, a wrong click!

There is no solution for this issue at all? react-hot-loader not working for classes and it's no way to fix it?

@neoziro Should this be re-opened if it was a mis-click? :stuck_out_tongue:

@Deadly0 it works fine for classes, it just fails with class property render methods;

class MyComponent extends React.Component {
  render() {
    return "This will hot reload fine!";
  }
}

class MyOtherComponent extends React.Component {
  render = function() {
    return "This will fail to hot reload!";
  }
}

Ok, I just start typing a long story why I have to idea how to solve this problem, and thus could not.
And then I got an idea how I could 🤷‍♂️

So the main thing here - there were no issues with the provided code. Only for the nested components, and even they possible were able to hot-reload themselves.
I had to spend some time to get red tests to fix them. Anyway - PR is opened.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sandysaders picture sandysaders  ·  4Comments

mtscout6 picture mtscout6  ·  3Comments

Opty1712 picture Opty1712  ·  4Comments

calvinchankf picture calvinchankf  ·  3Comments

rockchalkwushock picture rockchalkwushock  ·  3Comments