create-react-app: Minified React error #130 - 'this' in JSX arrow function

Describe the bug

It seems like there is some kind of scoping issue when using this in arrow function JSX.

The problem only occurs with production builds, not with dev server. This happens in a clean create-react-app project.

Below code breaks with Minified React error #130.

import React from 'react';

class App extends React.Component {

  Hello = props => <h1>Hello World</h1>;

  render = () => {

    return (
      <this.Hello/>
    );
  };
}

export default App;

Where as the two following examples work fine.

class App extends React.Component {

  Hello = props => <h1>Hello World</h1>;

  render = () => {

    let Component = this.Hello;

    return (
      <Component/>
    );
  };
}

class App extends React.Component {

  Hello = props => <h1>Hello World</h1>;

  render() {

    return (
      <this.Hello/>
    );
  };
}

Did you try recovering your dependencies?

This is on a fresh create-react-app project.

Which terms did you search for in User Guide?

Minifed React Error arrow function this this arrow function JSX this JSX arrow function

Environment

S3 bucket on AWS via CloudFront and using serve build locally.

Steps to reproduce

  1. npx create-react-app
  2. use a this in JSX in an arrow function.
  3. run yarn build
  4. run serve build
  5. open localhost:5000 and read console.

Expected behavior

To work the same as yarn start. Basically, not crash.

Actual behavior

image

Reproducible demo

import React from 'react';

class App extends React.Component {

  Hello = props => <h1>Hello World</h1>;

  render = () => {

    return (
      <this.Hello/>
    );
  };
}

export default App;

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 4
  • Comments: 23 (1 by maintainers)

Most upvoted comments

Update: I took the effort to extract a minimal repro, by ejecting and stripping it down to the minimum while still showing the error: https://github.com/sbusch/create-react-app-8738-repro

Here are my findings:

  • the problem is ultimately (but see also note below) caused by the Babel plugin @babel/plugin-transform-classes
  • in a create-react-app setup, this plugin gets added by Babel preset @babel/preset-env depending on the target browsers
  • solution/workaround (depending on your requirements):
    • disable @babel/plugin-transform-classes, OR
    • set { loose: true } option for @babel/plugin-transform-classes

The latter way would require some patching to get it into create-react-app, but I found a way for the former approach:

According to my tests, with the default browserslist (see package.json and
Configuring supported browsers)

browserslist: {
  production: [
    '>0.2%',
    'not dead',
    'not op_mini all'
  ]
}

just IE is causing @babel/preset-env to add @babel/plugin-transform-classes to the list of transforms. So if you can “afford” to ignore IE, the easiest workaround is to disable support for IE 11 by adding the exclusion 'not ie 11' to the browserslist in package.json like:

browserslist: {
  production: [
    '>0.2%',
    'not dead',
    'not op_mini all',
    'not ie 11'
  ]
}

Important: I recommend to delete node_modules/.cache after any change to the build setup, otherwise they won’t be picked up! (that cost me some hours 😕))

Notes:

  • although the problem is ultimately caused by @babel/plugin-transform-classes, it’s only happening in conjunction with @babel/plugin-transform-react-jsx and @babel/plugin-proposal-class-properties. Don’t know why (yet).
  • adding browserslist to the repro has no effect because I replace @babel/preset-env just with the plugin setup causing problems.
  • dev mode (via yarn run start) has been removed from the repro aswell to remove complexity

I plan to file an issue to Babel in the next few days, and will link it here.

I appreciate that there are newer and different ways of doing things. I’m not really trying to argue for any specific style or standard or which is better or not better. My point is, that existing code that worked before and is syntactically correct, no longer does.

I’m all for standards changing and all for migrating to newer better methods of work. If the intent was to completely stop supporting class components then a deprecation warning would be nicer than straight up breaking existing code. I don’t think that was the intent though.

On a side note, neither of your examples would work as replacements. Both just define a separate component that you can use, that’s not what’s happening here. Components are defined, built, derived, etc., on the class based on props. The working examples I showed, are fairly easy workaround for now. Again, whether this is a good or bad approach, is not the point. The point is large code bases can’t be changed overnight and will no longer work, even though no major versions were bumped.

Bump