讲道理,React中,咱们为何须要写 super(props)?

这篇文章源自 Dan 的博客javascript

如今的热点是 hooks,因此 Dan 决定写一篇关于 class 组件的文章 😂。html

文章中描述的问题,应该不会影响你写代码;不过若是你想深刻研究 React 是怎么工做的,这篇文章可能会对你有帮助。java

第一个问题:react


我本身都不知道我写了多少遍 super(props)git

class Checkbox extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isOn: true };
  }
  // ...
}
复制代码

固然,class 属性提案 能够简化代码:github

class Checkbox extends React.Component {
  state = { isOn: true };
  // ...
}
复制代码

2015 年初的时候,React 0.13 版本就已经计划支持该语法。在此以前,咱们须要不断地写 constructor,而后再调用 super(props)ide

如今咱们先回顾一下以前的写法:函数

class Checkbox extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isOn: true };
  }
  // ...
}
复制代码

咱们为何要调用 super?能不能不调用?若是调用的时候不传入props呢?还能够传入其余参数么?带着这些问题往下看。ui


在 JavaScript 中,super 引用的是父类构造函数。(在 React 中,引用的天然就是 React.Componentthis

须要注意的是,在调用父类构造函数以前,没法用 this。其实这不是 React 的限制,而是 JavaScript 的限制:

class Checkbox extends React.Component {
  constructor(props) {
    // 🔴 还不能用 `this`
    super(props);
    // ✅ 如今就能用啦
    this.state = { isOn: true };
  }
  // ...
}
复制代码

JavaScript 对 this 使用的限制,是有缘由的。假设有以下的继承:

class Person {
  constructor(name) {
    this.name = name;
  }
}

class PolitePerson extends Person {
  constructor(name) {
    this.greetColleagues(); // 🔴 不能这么干,下面会讲缘由
    super(name);
  }
  greetColleagues() {
    alert('Good morning folks!');
  }
}
复制代码

若是 JavaScript 容许在调用 super 以前使用 this,一个月以后,咱们须要修改 greetColleagues 方法,方法中使用了 name 属性:

greetColleagues() {
  alert('Good morning folks!');
  alert('My name is ' + this.name + ', nice to meet you!');
}
复制代码

不过咱们可能已经忘了 this.greetColleagues(); 是在调用 super 以前调用的;所以,this.name 尚未赋值。这样的代码,很难定位 bug。

为了不这样的错误,JavaScript 强制开发者在构造函数中先调用 super,才能使用this这一限制,也被应用到了 React 组件:

constructor(props) {
  super(props);
  // ✅ 如今能够用 `this` 啦
  this.state = { isOn: true };
}
复制代码

问题又来了:为何要传入 props 呢?


你可能觉得必须给 super 传入 props,不然 React.Component 就无法初始化 this.props

// Inside React
class Component {
  constructor(props) {
    this.props = props;
    // ...
  }
}
复制代码

en...离真相不远 —— 事实上,React 也的确这么干了

不过,若是你不当心漏传了 props,直接调用了 super(),你仍然能够在 render 和其余方法中访问 this.props(不信的话能够试试嘛)。

为啥这样也行?由于React 会在构造函数被调用以后,会把 props 赋值给刚刚建立的实例对象:

// Inside React
const instance = new YourComponent(props);
instance.props = props;
复制代码

props 不传也能用,是有缘由的。

React 添加对 class 支持的时候,不只仅要支持 ES6 的 class,还须要考虑其余的 class 实现, CoffeeScript, ES6, Fable, Scala.js, TypeScript 中 class 的使用方式并不一致。因此,即便有了 ES6 class,在调用 super()这个问题上,React 没作太多限制。

但这意味着你在使用 React 时,能够用 super() 代替 super(props) 了么?

别这么干,由于会带来其余问题。 虽然 React 会在构造函数运行以后,为 this.props 赋值,但在 super() 调用以后与构造函数结束以前, this.props 仍然是无法用的。

// Inside React
class Component {
  constructor(props) {
    this.props = props;
    // ...
  }
}

// Inside your code
class Button extends React.Component {
  constructor(props) {
    super(); // 😬 忘了传入 props
    console.log(props); // ✅ {}
    console.log(this.props); // 😬 undefined
  }
  // ...
}
复制代码

要是构造函数中调用了某个访问 props 的方法,那这个 bug 就更难定位了。所以我强烈建议始终使用super(props),即便这不是必须的:

class Button extends React.Component {
  constructor(props) {
    super(props); // ✅ We passed props
    console.log(props); // ✅ {}
    console.log(this.props); // ✅ {}
  }
  // ...
}
复制代码

上面的代码确保 this.props 始终是有值的。


还有一个问题可能困扰 React 开发者好久了。你应该已经注意到,当你在 class 中使用 Context API 时(不管是以前的 contextTypes 仍是如今的 contextType API),context 都是做为构造函数的第二个参数。

咱们为何不用写 super(props, context)?咱们固然能够这么写,不过 context API 用的相对较少,因此引起的 bug 也比较少。

感谢class 属性提案 ,这样的 bug 几近绝迹。只要没有显式声明构造函数,全部参数都会被自动传递。因此,在state = {} 表达式中,你能够访问this.props 以及 this.context

相关文章
相关标签/搜索