在React class组件中,为什么要写super(props)?

1,026 阅读2分钟

如果你习惯用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}`);
    }
}

但是我们忘了greetsuper(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); // -> {}
    }
}

很好,现在一切都正常了。