gaearon / react-transform-hmr

A React Transform that enables hot reloading React classes using Hot Module Replacement API
772 stars 57 forks source link

Freeze/continual-reloading when Component is aliased #82

Open Venryx opened 7 years ago

Venryx commented 7 years ago

I have a React Native project that uses hot-reloading. (Repo: https://github.com/Venryx/LucidLink)

I wrote a class named BaseComponent which extends the React.Component class.

However, when I do so, hot-reloading breaks. When I make a change within the render function of a component deriving from that BaseComponent class, react native tries to hot-reload, but ends up freezing the UI because it enters a loop of continually trying to update itself.

The Android logcat shows this (after a change) until I kill the app:

12-23 04:29:16.451 17424-17452/com.lucidlink I/ReactNativeJS: [React Transform HMR] Patching LucidLinkUI
12-23 04:29:16.462 17424-17452/com.lucidlink I/ReactNativeJS: [React Transform HMR] Patching LucidLinkUI
12-23 04:29:16.472 17424-17452/com.lucidlink I/ReactNativeJS: [React Transform HMR] Patching LucidLinkUI
12-23 04:29:16.482 17424-17452/com.lucidlink I/ReactNativeJS: [React Transform HMR] Patching LucidLinkUI
12-23 04:29:16.493 17424-17452/com.lucidlink I/ReactNativeJS: [React Transform HMR] Patching LucidLinkUI
12-23 04:29:16.504 17424-17452/com.lucidlink I/ReactNativeJS: [React Transform HMR] Patching LucidLinkUI
12-23 04:29:16.515 17424-17452/com.lucidlink I/ReactNativeJS: [React Transform HMR] Patching LucidLinkUI
12-23 04:29:16.527 17424-17452/com.lucidlink I/ReactNativeJS: [React Transform HMR] Patching LucidLinkUI

I thought I might have added something to my BaseComponent class that broke hot-reloading. But no. I removed all its code, and just had it extend Component (eg: class BaseComponent extends Component {}), and the issue remained.

I then thought, maybe some part checks whether the class name is "Component", and fails if it doesn't.

Not even that is true. I tried the following:

Before (hot-reloading works):

class MyComponent extends Component {
    ...
}

After (hot-reloading fails):

var AliasOfComponent = Component;
class MyComponent extends AliasOfComponent {
    ...
}

Yes, simply changing the variable name causes it to break! That doesn't make any sense unless it's somehow part of the compile process. (since all values referenced are exactly the same)

Any idea what's causing this, or what area of the react-native ecosystem to look in for the source of this bug?

Venryx commented 7 years ago

So I tried adding the code below to just before the "Patching ..." logging line (https://github.com/gaearon/react-transform-hmr/blob/master/src/index.js#L59):

global.lastUpdateTime = new Date().getTime();
if (new Date().getTime() - global.lastUpdateTime < 1000) return;

I now get the same issue shown here: https://github.com/facebook/react-native/issues/10991#issuecomment-264770349

The post below that says they fixed the issue by removing a circular dependency.

But... 1) If that's the problem, why does it only show up when the hot-loader tries to run, rather than the initial load? And is there any way to resolve it, without having to mess with the (otherwise working) dependency graph? 2) Also, if a circular-dependency is the problem, why does it only happen when I use an alias for Component, as shown above! It's very odd that just using an alias would be the final step to bring to fruition a "hidden" circular dependency issue. (it's very odd that it has any effect at all)