注:在
constructor
中必须调用super
方法,因为子类没有自己的this
对象,而是继承父类的this
对象,然后对其进行加工,而super
就代表了父类的构造函数。super
虽然代表了父类 A 的构造函数,但是返回的是子类 B 的实例,即super
内部的this
指的是 B,因此super()
在这里相当于 ```A.prototype.constructor.call(this, props)``。ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。
参考:new一个对象时,发生了什么?
ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面,然后再用子类的构造函数修改this。所以必须先调用super方法,否则javascript引擎会报错。
上边的话可能不好理解,super方法目的调用父类构造函数但是返回的的this 是给子类b用的,已经带上了父类属性和方法。故是A的原型对象的构造函数使用B的this调用。
1.__proto__和constructor属性是对象所独有的。
2.prototype属性是函数所独有的,但是由于js中函数也是一种对象,所以函数也拥有__proto__和constructor属性.
3.__proto__属性的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的__proto__属性所指向的原型对象里面找,如果仍未找到则会继续层层向上查找,直到找到该属性或者查找到顶端null为止;通过__proto__属性将对象连接起来的这条链路就是原型链。
prototype属性的作用就是让该函数所实例化的对象们都可以找到公用的属性和方法,即(new F()).proto === F.prototype。
4.constructor表示一个对象的构造函数,js的数据类型中除了null跟undefined都有这个属性,所有函数(此时看成对象了)最终的构造函数都指向Function。
现在我们写基于类的组件没有构造函数,我们也可以在构造函数之外写状态。在旧版本的React中,我们使用的状态总是在构造函数中。
正如我们从名字中可以理解的那样,这个方法从props中派生出一个状态。getDerivedStateFromProps()方法是在DOM中呈现组件之前调用的。这是根据初始props设置状态对象的正确位置
静态方法,无法通过 this 访问实例属性
作用为组件在 props 发生改变时更新它自身的内部 state
在挂载和更新阶段都会执行,执行时机为 render 阶段
constructor(props) {
super(props)
// we can write state inside or outside the constructor
// if is written outside the constructor it does not need the keyword this
this.state = {
firstName: 'John',
}
}
static getDerivedStateFromProps(props, state) {
return { firstName: props.firstName }
}
static getDerivedStateFromProps(nextProps, prevState) {
const {type} = nextProps;
// 当传入的type发生变化的时候,更新state
if (type !== prevState.type) {
return {
type,
};
}
// 否则,对于state不进行任何操作, 依然会发生渲染,只是state不做更新而已
return null;
}
当我们创建一个基于类的组件时,render方法是必需的。render方法是我们返回JSX的地方。只要状态发生更改,render方法就会进行渲染。不要在render方法中设置状态。
正如我们可以理解的方法的名称,该方法调用组件后呈现。这是一个设置时间间隔和调用API的地方。查看componentDidMount方法中的以下setTimeout实现。
componentWillMount
在服务端渲染(nuxt.js)的时候会导致服务端和客户端各渲染一次,而componentDidMount
只在客户端渲染一次。componentDidMount() 会在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。
这个方法是比较适合添加订阅的地方。如果添加了订阅,请不要忘记在 componentWillUnmount() 里取消订阅
你可以在 componentDidMount() 里直接调用 setState()。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在 render() 两次调用的情况下,用户也不会看到中间状态。请谨慎使用该模式,因为它会导致性能问题。通常,你应该在 constructor() 中初始化 state。如果你的渲染依赖于 DOM 节点的大小或位置,比如实现 modals 和 tooltips 等情况下,你可以使用此方式处理
componentDidMount
是一个会阻塞渲染的生命周期,我们在这里面最好不要去执行一些非常耗时的逻辑,这样会让我们的首屏出现的更慢。浏览器js线程和渲染线程是互斥的 执行js线程时是无法去触发渲染的,上边说该生命周期会在挂载后立刻执行,此时只是挂载上去并没有渲染出来,然后立刻执行js,渲染进程被阻塞,此时页面是白的,拿到数据然后setState此时是同步渲染的,会触发一次额外渲染,然后就不会出现初始化的状态值。
事件监听最好在
componentDidMount
来实现,因为只有在调用componentDidMount
的时候,React才会确保componentWillUnmount
回调能顺利执行,防止内存泄漏。等同于 useLayoutEffect hook
https://zhuanlan.zhihu.com/p/388636591 写的非常好直白
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
与挂载阶段类似,getDerivedStateFromProps也可以在更新阶段调用。getDerivedStateFromProps是组件更新时调用的第一个方法。
简单的说就是此处可以确定拿到父组件传过来的跟新的props
这个函数会在每次re-rendering之前被调用,这意味着什么呢?意味着即使你的props没有任何变化,而是父state发生了变化,导致子组件发生了re-render,这个生命周期函数依然会被调用。
// 在getDerivedStateFromProps中进行state的改变
static getDerivedStateFromProps({ error, value }, state) {
/* Keep last received error in state */
if (error && error !== state.error) {
return { error };
}
if (value && value !== state.text) {
return { text: value }
}
return null;
}
shouldComponentUpdate(nextProps, nextState)内置的生命周期方法应该返回一个布尔值。如果此方法不返回true,则应用程序将不会更新。
如果方法不返回true,应用程序将永远不会更新。这可以用于例如在达到某个点(游戏、订阅)时阻止使用,或者可以用于阻止某个用户。
getSnapshotBeforeUpdate 会在最终的 render 之前被调用,也就是说在 getSnapshotBeforeUpdate 中读取到的 DOM 元素状态是可以保证与 componentDidUpdate 中一致的。
此生命周期返回的任何值都将作为参数传递给componentDidUpdate()。更新前,因为可以记录一些 dom 数据,传给 componentDidUpdate在最近一次渲染输出(在 before mutation 中)之前调用,dom 还没有更新,一般用作 UI 处理
snapshot:接受 getSnapshotBeforeUpdate()的返回值
在屏幕更新后调用,在 commit 阶段的 layout 阶段同步执行。
在 componentDidUpdate 中改变 state 应该是有条件的,不然会死循环
可以在此处对比更新前后的 props 和 state
会在组件卸载及销毁之前直接调用
此生命周期会在后代组件抛出错误后被调用
它将抛出的错误作为参数,并返回一个值以更新 state
在渲染阶段调用,不允许出现副作用
此生命周期在后代组件抛出错误后被调用
在“提交”阶段被调用,因此允许执行副作用。 它应该用于记录错误之类的情况