React老的生命周期总体简述
1、初始化阶段
constructor();constructor函数在业界把它放入生命周期函数是存疑的,这里我是倾向于放入生命周期函数的,官方也是把它放在挂载阶段的,这个个函数里我们可以继承父组件的props和初始化组件的state。
componentWillMount:render之前最后一次修改状态的机会,在16.2版本之后被废弃要使用需要加上UNSAFE_的前缀。
render:只能访问this.props和this.state,不允许直接修改状态和DOM。
componentDidMount:成功render并渲染完成真实DOM之后触发,可以修改DOM。
2、运行中阶段
componentWillReceiveProps:父组件修改属性会触发该周期函数
shouldComponentUpdate:返回false会阻止render调用,这里一般做class组件的性能优化的工作。
componentWillUpdate:在这个周期函数内不能修改属性和状态。
render:只能访问this.props和this.state,不允许直接修改状态和DOM。
componentDidUpdate:可以修改DOM。
3、销毁阶段
componentWillUnmount:在删除组件之前进行清洗操作,比如销毁计时器和事件监听器
注意:大部分的生命周期函数是在新版本复用的,但是有些生命周期函数是React不推荐使用的。具体包括如下:
a、初始化阶段的 UNSAFE_componentWillMount(),这里的意思是componentWillMount()周期函数加了UNSAFE_的前缀。
b、更新阶段的UNSAFE_componentWillUpdate()、UNSAFE_componentWillReceiveProps()
一共是这三个周期函数被遗弃了,要使用必须加上UNSAFE_,不然react会报警告。
React老的生命周期具体剖析
初始化阶段的constructor()
constructor(props){
super(props)
//注意:在派生类中,必须先调用 super() 才能使用 "this"。
this.state={
value:'Bob'
}
}
在constructor函数里注意要加super().具体原因分析如下:
a、constructor 是一种用于创建和初始化class创建的对象的特殊方法。
b、在一个类中只能有一个名为 “constructor” 的特殊方法。多个会报错。
c、在一个构造方法中可以使用super关键字来调用一个父类的构造方法。
d、如果没有显式指定构造方法,则会添加默认的 constructor 方法。
e、如果不指定一个构造函数 (constructor) 方法,则使用一个默认的构造函数 (constructor)。
f、如果不指定构造方法,则使用默认构造函数。对于基类,默认构造函数是:
constructor() {}
对于派生类,默认构造函数是:
constructor(...args) {
super(...args);
}
构造函数的形式有上面两种形式。由此可以内推,我们在react中的class组件里,使用构造函数,是一个派生类的构造函数,它的基类是React.Component,所以要写super去调用父类的构造函数,并把props传递给子类。注意:在派生类中,必须先调用 super() 才能使用 "this"。所以才可以给state去初始化赋值,不然this.state会报错。
初始化阶段的componentWillMount()
UNSAFE_componentWillMount() 在挂载之前被调用。它在 render() 之前调用,因此在此方法中同步调用 setState() 不会触发额外渲染,这个是我们在render之前最后一次有机会修改state。通常,我们建议使用 constructor() 来初始化 state。
注意:不要在此周期函数中引入订阅和修改DOM。此周期函数是服务端渲染唯一会调用的生命周期函数。
初始化阶段的render()和更新阶段的render()
a、render()是class组件中唯一必须实现的方法。 b、render()是纯函数,不能在这个周期函数中修改组件的props和state,也不直接做操作dom的操作,如要操作dom要迁移到其他周期函数中。 c、render()的在组件每次调用setState去改变state都会触发render()重新渲染。 d、render()里return返回的是一个最外面没有并列节点的React 元素,代码描述下会更清晰
render() {
return (
<div>
{/* <HelloWorld /> */}
{/* <HelloWroldState /> */}
{/* <Range/> */}
{/* <NewRange/> */}
{/* <NewRangeDemo/> */}
{/* <MyInput/> */}
{/* <Parent/> */}
{/* <EvenBus/> */}
{/* <ContextPage/> */}
<MySlot/>
</div>
)
}
由最外层div包裹。
初始化阶段的 componentDidMount
a、这个个周期函数表示在组件挂载后(组件插入DOM树后),会立即触发。
b、操作DOM节点的操作应该放在这里。
c、这里可以添加订阅,注意要在销毁周期函数中取消订阅。
d、不建议在此初始化state状态,因为在此直接调用setState会触发额外的渲染。
更新阶段的 componentWillReceiveProps
a、会在已挂载的组件接收新的 props 之前被调用,注意:父组件修改属性会触发该周期函数。
b、UNSAFE_componentWillReceiveProps(nextProps)
这里会取到最新的props。在这个周期函数中可以比较 this.props 和 nextProps 并在此方法中使用 this.setState() 执行 state 转换
c、这个方法也是被遗弃的需要加前缀。
d、由于新版React引入了react Fiber架构去实现增量渲染,渲染颗粒度更小,该周期函数的执行优先度较低,在海量数据的时候会把这个周期函数给挤掉。
更新阶段的 shouldComponentUpdate(nextProps, nextState)
a、默认行为是 state 每次发生变化组件都会重新渲染。大部分情况下,你应该遵循默认行为,但是如要减少渲染的话就要返回false。
b、当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。返回值默认为 true。
更新阶段的 componentWillUpdate
当组件收到新的 props 或 state 时,会在渲染之前调用
更新阶段的 componentDidUpdate(prevProps, prevState, snapshot)
a、componentDidUpdate() 会在更新后会被立即调用。首次渲染不会执行此方法。
b、可以在 componentDidUpdate() 中直接调用 setState(),但请注意它必须被包裹在一个条件语句里
销毁阶段的componentWillUnmount()
a、componentWillUnmount() 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。
b、componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。
下面是一个运行部分生命周期的例子:
import React, { Component } from 'react'
export default class Range extends Component {
constructor(){
super()
this.state={
name:'qq'
}
}
// 第一次将要挂载到dom上,可以最后一次修改state
componentWillMount(){
console.log('第一次componentWillMount',this.state.name)
this.setState({
name:'7uuu'
})
}
//
componentDidMount(){
console.log('第一次componentDidMount',this.state.name)
// 数据请求放在这
//订阅函数的订阅
//setInterval
//基于创建完的dom进行初始化,。。。。。比如BetterScroll组件new出来
}
shouldComponentUpdate(nextProps,nextState){
// return true;//更新组件
// return false // 阻止更新
//this.state 老的状态
//nextState 新的状态
// if(老的状态 !== 新的状态) {
// return true
// }
// return false
if(JSON.stringify(this.state)!==JSON.stringify(nextState)){
return true
}
return false
}
render() {
return (
<div>
<div>range</div>
<button onClick={()=>{
this.setState({name:'3d33'})
}}>change</button>
<div>{this.state.name}</div>
</div>
)
}
}