如果你习惯用class写React组件,想必不会对super(props)感到陌生。
class App extends React.Component {
constructor(props) {
super(props);
this.state = { ... };
}
}
当然,class fields proposal 让我们可以省略构造函数:
class App extends React.Component {
state = { ... };
}
但是,让我们回到带有构造函数的例子。
我们都知道,super表示的是父类的构造函数。
那么,我们在当前组件的构造函数里面,为什么要调用父类的构造函数呢?
如果不调用会怎么样?
又或者,调用时不传入props会怎么样?
首先,在constructor里面,在调用super()之前,this是不能使用的:
class App extends React.Component {
constructor(props) {
// 这里还不能用this
super(props);
// 现在可以用this了
this.state = { ... };
}
}
其实这么做是有原因的。现在我们假设super()调用前可以正常使用this,考虑以下代码:
class Animal {
constructor(name) {
this.name = name;
}
}
class Cat extends Animal {
constructor(name) {
this.greet();
super(name);
}
greet() {
console.log("Hello I'm cat");
}
}
两个月之后,我们把Cat类改成:
class Cat extends Animal {
constructor(name) {
this.greet();
super(name);
}
greet() {
console.log(`Hello I'm ${this.name}`);
}
}
但是我们忘了greet在super(name)执行前已经被调用,此时this.name还没有被定义!
而且这类问题非常难以定位!
因此JS规定super()前不允许使用this,以避免落入类似陷阱。
那么接来下,让我们看看为什么super(props)要传入props,如果不传会怎么样。
通过React 源码 我们可以看到,React把props赋给了this.props:
this.props = props;
所以如果不传入props,那么我们就不能读取到this.props?
其实,即使不传入props,在render()等方法里面,this.props依然是可以正常读取到的(不信你可以试试)。
这是因为在React内部,做了类似这样的处理:
const instance = new YourComponent(props);
instance.props = props;
所以在render()等方法里面依然可以正常获取this.props。
只是,在constructor中不能:
class App extends React.Component {
constructor(props) {
super(); // 没有传入props
console.log(props); // -> {}
console.log(this.props); // -> undefined
}
}
所以,最好还是每次都把props带上,第一避免让人困惑,第二避免出现意外。
class App extends React.Component {
constructor(props) {
super(props); // 传入了props
console.log(props); // -> {}
console.log(this.props); // -> {}
}
}
很好,现在一切都正常了。