ES6 Components that extend React.Component are always shown as the base class
Closed this issue · 15 comments
// The base class
class ViewComponent extends React.Component { }
// The react components that are used.
class Header extends ViewComponent { render() {} }
class Content extends ViewComponent { render() {} }
Now both <Header>
and <Content>
are shown in React Developer Tools as ViewComponent
. This makes the whole DevTools quite useless when you have a base class for all components inherit from, since everything that's shown in DevTools are ViewComponents.
What is shown is the 'displayName' of your component. I assume Babel adds a displayName automatically to subclasses of React.Component, but not to other classes. You can add a displayName manually to your classes, or come up w/ a babel plugin that will add a displayName to all classes.
As an aside, I suggest against inheritance in general :) composition + class factories serve me very well.
@prasannavl Hidden deep in the comments of facebook/react#5618 (comment) is a mention of the fact that we should display the element name in addition to the class displayName (this is something we want to do). I know this isn't a clean solution to your original issue, but it might mitigate your issue.
I am probably not technical enough to really help, but when I had my code setup using ES6 classes every tag was shown as T, changing the code back to var Name = React.createClass({})
fixed the react dev tools.
@prasannavl : I have been working around this issue by setting the name to a static property called "displayName" based on @jimfb 's input.
I'm pretty new to this whole ecosystem, but I was curious if this is the same reason that decorators don't seem to work. See example: http://gaearon.github.io/react-dnd/examples-chessboard-tutorial-app.html or is that a separate issue?
@gaearon Doh. I'm dumb. Thanks for the insights!
Finally I figured out why I keep getting error messages about the wrong component!
If all your components extend from a base class as @prasannavl mentioned, it will be obvious that something is wrong. But if you mostly extend from Component
and you only have some classes extend each other, then it will be not that obvious at all and the error message can be real confusing!
So I tried what happened if I just delete
the displayName from the component class after it has been created:
export class BaseComponent extends Component { /* ... */ }
delete BaseComponent.displayName;
export class DerivedComponent extends BaseComponent { /* ... */ }
This works!
Both in error messages as well as in the React dev tools, the name of the component is correct down the whole class hierarchy.
I think the displayName
feature is ok as it is, but that Babel should actually not add that property for regular ES6 classes extending Component
as React can already get the name from the class name.
@gaearon Any motivations for that? It seems to be working just fine except for this issue.
It’s just unnecessary because React already has a strong composition model. Inheritance hierarchies generally don’t scale well to complex UIs.
Here’s an example of solving a problem with inheritance:
import { Component } from 'react';
class BaseButton extends Component {
componentDidMount() {
console.log('hey');
}
render() {
return <button>{this.getContent()}</button>;
}
}
class RedButton extends BaseButton {
componentDidMount() {
super.componentDidMount();
console.log('ho');
}
getContent() {
return 'I am red';
}
render() {
return (
<div className='red'>
{super.render()}
</div>
);
}
}
In our experience this is hard to maintain.
This is also not how we intend React to be used.
In React you can express the same by passing props:
import { Component } from 'react';
class Button extends Component {
componentDidMount() {
console.log('hey');
}
render() {
return (
<div className={this.props.color}>
<button>{this.props.children}</button>
</div>
);
}
}
class RedButton extends Component {
componentDidMount() {
console.log('ho');
}
render() {
return (
<Button color='red'>
I am red
</Button>
);
}
}
In our experience this is simpler and more flexible because you don’t have the “fragile base class” problem.
Going to close this, but let me know if you still have issues.
There is an edge case you might hit (base class has displayName
but descendant only has a name
). We could conceivably check if displayName
is own property, and if it's not but name
is available, prefer name
. If you're interested in implementing this, please send a PR!
I have similar issue when passing class instance to component's props.
In short, I'm doing smth like this:
class A { ...whatever... }
class B extends A {
constructor() {
super()
this.some = {}
}
get foo() {
return this.some.value
}
}
<MyComponent the_instance={new B()} />
Then, devtools shows me correct info:
When accessing in console $r.props.the_instance.foo
, it also works normal:
BUT when expanding the_instance
prop in devtool's sidebar, smth strange happens:
Now it's an instance of not B
but A
, and obviously crashes because can't read property of undefined.
Not fatal, but annoying thing, which complicates debugging.
My .babelrc
, if it can help:
{
"presets": [
[ "env", {
"targets": {
"browsers": [
"last 2 versions"
]
},
"useBuiltIns": true
}],
"react"
],
"plugins": [
"syntax-dynamic-import",
"transform-object-rest-spread",
[ "transform-runtime", { "polyfill": false } ],
[ "transform-builtin-extend", {
"globals": [ "Error" ]
}],
"transform-decorators-legacy",
"transform-class-properties",
"transform-async-generator-functions"
],
"env": {
"development": {
"plugins": [
"transform-react-jsx-source"
]
}
}
}
I think you have hit an actual issue. But I also think it would be better for you to create a new issue and just reference this one. I am still watching this issue because I once posted here, but many maintainers will never see your issue if you add it to a closed topic. And as I think you really hit something here, it should be ok to just create a new issue for it. You can just add a hash sign and the issue number of this issue to your new issue to refer people back here for background info. Like this:
#308
: #308
My € 0,02.