react-native: Hot reloading (HMR) not working with functional components

Description

Hot reloading doesn’t work on functional components. The “hot loading” message appears, but the changes don’t show up.

Reproduction

react-native init test
cd test

Open index.android.js and replace :

export default class test extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <Text style={styles.instructions}>
          To get started, edit index.android.js
        </Text>
        <Text style={styles.instructions}>
          Double tap R on your keyboard to reload,{'\n'}
          Shake or press menu button for dev menu
        </Text>
      </View>
    );
  }
}

with

const test = () => (
  <View style={styles.container}>
    <Text style={styles.welcome}>
      Welcome to React Native!
    </Text>
    <Text style={styles.instructions}>
      To get started, edit index.android.js
    </Text>
    <Text style={styles.instructions}>
      Double tap R on your keyboard to reload,{'\n'}
      Shake or press menu button for dev menu
    </Text>
  </View>
);

Enable hot reloading, reload the app and try to make changes.

Additional Information

  • React Native version: 0.37.0
  • Platform: Android (didn’t try ios)
  • Operating System: Windows

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 67
  • Comments: 53 (9 by maintainers)

Most upvoted comments

This has been fixed on master with a new implementation we’re calling Fast Refresh. https://mobile.twitter.com/reactnative/status/1144629612921720833

It will be a part of the 0.61 release. I’m going to close this issue.

+1

still a real issue, still very annoying.

A similar issue exists with auto-bound class property functions:

import React from 'react';
import {View, Text} from 'react-native';

export default class HotReloadingTest extends React.Component {
  constructor(props) {
    super(props);

    this.manualBind = this.manualBind.bind(this);
  }

  render() {
    return (
      <View style={{flex: 1, paddingTop: 20}}>
        <View style={{flex: 1, backgroundColor: 'rgba(0, 255, 0, 0.1)'}}>
          {this.manualBind()}
        </View>
        <View style={{flex: 1, backgroundColor: 'rgba(255, 0, 0, 0.1)'}}>
          {this.autoBind()}
        </View>
      </View>
    );
  }

  manualBind() {
    return (
      <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
        <Text>Manual reloads fine</Text>
      </View>
    );
  }

  autoBind = () => {
    return (
      <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
        <Text>Auto doesn’t hot reload</Text>
      </View>
    );
  }
}

kapture 2017-08-04 at 12 42 21

Any update?

@jrwpatterson It’s still not working for me on 0.59

HMR appears to work for all components that are beneath at least one class component. So I made my root component a class, and now HMR is still working even with SFCs below. Hope this helps someone!

🙁 this makes HMR totally useless. Any idea wether https://github.com/facebook/react-native/issues/15363 could be fixed with a similar babel plugin?

@pie6k Try my babel plugin https://github.com/bvic23/babel-plugin-functional-hmr until the issue is fixed.

Especially painful when working with react-navigation b/c it’s almost all composed of functional components that don’t reload on save. I think this is a solid dev experience pain point - cc @grabbou is there anything to be done here?

I’m seeing the same issue with PureComponent. Let me know if that’s unrelated and I can file a different issue — I’m not clear on why #9152 was closed.

@tlvince I was experiencing the same issue and fixed it after finding and removing a circular dependency in my project. I noticed that the “Maximum call stack exceeded” was only being thrown when I edited files under a certain level in my “dependency tree”.

Not sure it’s correct behaviour for the Hot Loading but it could be what is happening in your case too.

did this get fixed I still have it and with react-native 57 on babel7 the above plugin isn’t working for me?

This is still not working, I confirm that functional component break the screen: “react-native”: “0.57.5”, “react”: “16.6.1”,

I have to constantly reload by hand because hot reload crashes and displays red screen.

Capture

did this get fixed in 59?

@lsps9150414

renderSomeText = () => {
  console.log('render Some Text');
  return (<Text>Some Text</Text>);
}

doesn’t hot reload because of the way the code is transpiled into the constructor before hot reload can proxy it. I can’t find the source for it anymore, but can confirm from personal experience.

constructor(props) {
    super(props);
    this.renderSomeText = this.renderSomeText.bind(this);
  }
function renderSomeText(){
  console.log('render Some Text');
  return (<Text>Some Text</Text>);
}

works differently, you can run your app in debug mode and step through it to see what it’s doing when hot reload is enabled.

https://facebook.github.io/react-native/blog/2016/03/24/introducing-hot-reloading.html#react-components might help you understand how it works better.

What @kristojorg said is true - the HMR does indeed detect changes functional components and reloads the app correctly, however there is a caveat to this: it will reload the closest parent class based component, not the component itself. So if you make your root component a class based one, every time you change one of your functional components it will reload from the root down, instead just the component you changed.

I think it has gotten worse actually. Im seeing it crash even when HMR is off and live reloading is enabled. Every save, crash.

hot reloading in PureComponents is totally fixed for me in RN v0.50 https://github.com/facebook/react-native/issues/9152

Same issue here, about the bound functions.

What I’ve been doing is to force unmount the component and mount it back again, by going to another screen and back. At least it’s faster than a full reload.

Reading https://facebook.github.io/react-native/blog/2016/03/24/introducing-hot-reloading.html

The default transformer that comes with React Native uses the babel-preset-react-native, which is configured to use react-transform the same way you’d use it on a React web project that uses Webpack.

Looks like that transformer library historically had issues with hot reloading functional components according to https://github.com/gaearon/babel-plugin-react-transform/issues/57

I can guess both iOS and Android will be broken, this seems purely like a limitation of the JavaScript transformation process.