I hear Hooks are the new focus. However, I want to use this blog post to show you what’s interesting about the class declaration component. What do you think?
The following does nothing to improve your React skills. But when you dig deeper into how things work, you’ll find the joy they bring.
Let’s look at the first example.
I wrote super(props) a lot more than I thought:
class Checkbox extends React.Component {
constructor(props) {
super(props);
this.state = { isOn: true };
}
// ...
}
Copy the code
Of course, the Class Fields Proposal allows us to skip this process:
class Checkbox extends React.Component {
state = { isOn: true };
// ...
}
Copy the code
This was in 2015, with the addition of support for the class syntax planned in the act0.13 release. Declaring constructor and calling super(props) has been used as a temporary solution until a more reasonable alternative, class Fields, is developed.
But before we do that, let’s go back to the ES2015 only example:
class Checkbox extends React.Component {
constructor(props) {
super(props);
this.state = { isOn: true };
}
// ...
}
Copy the code
Why callsuper
? We canDon’tCall it? If we have to call it, we don’t call itprops
What’s going to happen? Will there be more parameters? Let’s find out.
In JavaScript, super is a reference to the parent class constructor. (In our case, it points to React.Component.)
It is important to note that you cannot use this from constructor before the constructor call from the parent class. JavaScript does not allow you to do this:
class Checkbox extends React.Component {
constructor(props) {
// π΄ Canβt use `this` yet
super(props);
// β
Now itβs okay though
this.state = { isOn: true };
}
// ...
}
Copy the code
There is a reason why JavaScript forces the parent class constructor to be executed before you touch this. Think of the class hierarchy:
class Person {
constructor(name) {
this.name = name; }}class PolitePerson extends Person {
constructor(name) {
this.greetColleagues(); // π΄ This is disallowed, read below why
super(name);
}
greetColleagues() {
alert('Good morning folks! '); }}Copy the code
Assume that this is allowed before super. A month later, we might add the name attribute to greetColleagues’ messages:
greetColleagues() {
alert('Good morning folks! ');
alert('My name is ' + this.name + ', nice to meet you! ');
}
Copy the code
However we forgot to declare that this.greetcolleagues () was called before the super method of this.name was called. So that this.name becomes undefined! As you can see, the code becomes harder to guess.
To avoid this trap, JavaScript forces you to call super first if you want to use this in constructor. Let the parent do its job first! This limitation also applies to defining other React components:
constructor(props) {
super(props);
// β
Okay to use `this` now
this.state = { isOn: true };
}
Copy the code
There’s another question, why are we passing props?
You might think that the reason for passing props in super is to initialize this. Props in react.componentconstructor:
// Inside React
class Component {
constructor(props) {
this.props = props;
// ...}}Copy the code
In fact, that’s pretty much the reason. That’s the exact reason.
But in some cases, you can still get this.props in render and other methods, even if you don’t pass props when calling super. (If you don’t believe me, try it yourself!)
How does this work? The reason is that after your component is instantiated, it assigns the props property to the instance object.
// Inside React
const instance = new YourComponent(props);
instance.props = props;
Copy the code
So even if you forget to pass props to super, React will still set them later, for a reason.
When React added support for classes, it didn’t just add support for ES6, the goal was to support as broad a class abstraction as possible. It wasn’t clear at the time how ClojureScript, CoffeeScript, ES6, Fable, Scala.js, TypeScript, or any other solution would successfully define a component, React doesn’t care if super() needs to be called — even in ES6.
So can you just use super() instead of super(props)?
Better not. Because that’s still a problem. Yes, React can be given after your constructor runthis.props
The assignment. butthis.props
In the callsuper
And constructor remain before the endundefined
:
// Inside React class Component { constructor(props) { this.props = props; / /... } } // Inside your code class Button extends React.Component { constructor(props) { super(); // π¬ We forgot to pass props console.log(props); / / β
{} the console. The log (enclosing props); // π¬ undefined} //... }Copy the code
If this is the case for some method in constructor, it becomes difficult to debug. That’s why I always recommend adding super(props), even if it’s not needed:
class Button extends React.Component {
constructor(props) {
super(props); // β
We passed props
console.log(props); / / β
{}
console.log(this.props); / / β
{}
}
// ...
}
Copy the code
This ensures that this. Props is assigned before constructor completes.
One final point that React users may have wondered about for a long time.
You may notice that when you use the Context API in a class (either the contextTypes of the past or the contextTypeAPI added later in React 16.6, the Context is passed as the second constructor argument).
So why don’t we say super(props, context) instead? Well, we can, but context is used less often, so we don’t get as many pits.
When class Fields proposal is made, most of the pits will disappear. Without constructor, all parameters are passed in automatically. This allows expressions like state = {}, if needed, this.props or this.context.
In Hooks, we don’t even need super or this. But that’s for another day.
Why Do We Write super(props)?