Class组件的生命周期
生命周期描述的是组件从创建到卸载的一个完整过程。React提供了一系列生命周期函数,如:初次渲染到DOM中,组件更新完成,组件卸载之前等。
React组件的生命周期分为三个阶段
1)挂载阶段(Mounting),这个阶段会从组件的初始化开始,一直到组件创建完成并渲染到真实的DOM中
2)更新阶段(Updating),这个阶段从组件开始更新,一直监测到组件更新完成并重新渲染完DOM
3)卸载阶段(Unmounting),这个阶段监听组件从DOM中卸载
组件的挂载阶段
会依次调用以下生命周期函数
1、constructor(props),在constructor中,会初始化该组件,继承自Component类,不要忘了加super
2、static getDerivedStateFromProps(props,state),该方法用于从props中获取state,在挂载阶段该方法可以获取到当前的props和state,然后根据props来对state进行修改。使用时注意以下几点:
- 该方法是静态方法,使用时其内部不能使用this
- 该生命周期函数是在React16.3之后新增的,使用其注意版本
- 必须有返回值,其返回值是对state的修改,相当于其他地方调用this.setState()时,传入的修改对象
- 其作用是根据props来修改state的,所以组件初始化时要定义state属性
3、componentWillMount,代表组件即将要挂载,使用时注意:
- 在React16.3之后不建议使用
- 其和getDerivedStateFromProps不能同时使用
4、render。该方法尤为重要,会根据return中的值生成虚拟DOM,然后提交给ReactDOM,渲染真实的DOM
5、componentDidMount,组件已经挂载完毕,虚拟DOM已经添加到真实的DOM中
以上方法是组件在挂载阶段会调用的生命周期函数,按照顺序依次是:constructor->getDerivedStateFromProps或componentWillMount->render->componentDidMount
组件更新阶段
即调用了setState等方法引起了组件的更新
React组件更新的生命周期有三种不同的过程
父组件更新引起的当前组件更新、当前组件自己更新、forceUpdate
1、父组件更新
父组件更新同样会引起当前组件更新。由于父组件更新带动当前组件更新会调用的生命周期函数,在React16.3以及之后和React16.3之前略微有些差异
React16.3之前
1)componentWillReceiveProps(nextProps),该生命周期函数在父组件更新后子组件接收到新的Props时触发。在该函数中调用的this.prop结果还是更新前的props,更新后的使用nextProps
2)shouldComponentUpdate(nextProps,nextState),该方法用于判断是否要进行组件的更新。同WillReceiveProps一样,这时获取this.props和this.state是更新前的props和state。另外此方法必须有返回值,而且是个布尔值,用来定义组件是否更新,返回值为true时,生命周期会继续向下进行,组件继续更新;返回值为false时,则停止组件更新,不会调用后续的生命周期函数
3)componentWillUpdate(nextProps,nextState)组件即将更新。props和state的相关使用同2)一样
4)render根据新的props和state生成虚拟DOM,然后将新的虚拟DOM和旧的虚拟DOM对比找出更新点,更新真实的DOM。在该方法中的this.props和this.state都是更新过后的值
5)componentDidUpdate(prevProps,prevState),该方法代表组件已经更新完毕,真实的DOM已经完成重新渲染。在该方法中想要获取更新前的props和state的话,可以通过参数接收。
React16.3之前,父组件更新引起子组件更新,所调的生命周期顺序:componentWillReceiveProps->shouldComponentUpdate->componentWillUpdate->render->componentDidUpdate
React16.3及以后
在React16.3中使用getDerivedStateFromProps方法替换掉componentWillReceiveProps。另外从React16.3开始,componentWillReceiveProps和componentWillUpdate逐渐被废弃掉,如果到React17.x中还想使用相关方法加上前缀UNSAFE_,并且组件中使用了getDerivedStateFromProps之后,componentWillReceiveProps和componentWillUpdate也不会执行。React16.3之后由父组件更新引起的组件更新如下:
1)static getDerivedStateFormProps(newProps,newState)在更新阶段,可以获取到新的props和state,同样返回值也是对state的修改
2)shouldComponentUpdate判断组件是否更新
3)render生成新的虚拟DOM
4)getSnapshotBeforeUpdate(prevProps,prevState),这个方法是React16.3新增加的,该方法执行在render生成虚拟DOM之后,渲染真实DOM之前,用于获取渲染前的DOM快照
- getSnapshotBeforeUpdate中的this.state和this.props已经更新为新的props和state,想要获取更新前的可以从参数中获取
- getSnapshotBeforeUpdate必须有返回值,其返回值会传递给componentDidUpdate
5)componentDidUpate(prevProps,prevState,snapshot)在React16.3中,新增加了第三个参数snapshot,用于接收getSnapshotBeforeUpdate通过返回值传递过来的信息
React16.3及以后对更新阶段的生命周期函数调用顺序为:static getDerivedStateFromProps->shouldComponentUpdate->render->getSnapshotBeforeUpdate->componentDidUpdate
2、组件自己更新
组件自己更新即在组件内部调用了setState,引起当前组件更新。组件自己更新流程在React中已经经历了三个版本:React16.3之前、React16.3、React16.4及以后
1)React16.3之前,当前组件自己更新会一次调用下列函数:shouldComponentUpdate->componentWillUpdate->render->componentDidUpdate。这里看到组件自己更新已经不在监听props变化,只监听state的修改
2)在React16.3中,由于生命周期函数有变化,所以组件自己更新所调用的函数也跟着变化,依次调用过程为:shouldComponentUpdate->render->getSnapshotBeforeUpdate->componentDidUpdate
3)React16.4及以后,为了更方面开发者,官方又做了一个调整,把组件自己更新和父组件更新带来的组件更新做了统一,顺序为:static getDerivedStateFormProps->shouldComponentUpdate->render->getSnapshotBeforeUpdate->componentDidUpdate
3、forceUpdate
除了使用setState更新组件以及父组件更新带来的更新外,React还有一种更新组件的方式——强制更新(forceUpdate)。当组件依赖的数据不是state时,数据改变了,此时希望视图也进行改变就可以使用forceUpdate方法了
let name = 'name';
class App extends Component {
render(){
return <div>
<p>{name}</p>
<button onClick={()=>{
name = '新名字';
this.forceUpdate();
}}>
更新名字
</button>
</div>
}
}
forceUpdate会强制视图进行更新,所以生命周期跟其他的梗系略有不同,不会在调用shouldComponentUpdate
组件的卸载阶段
即把组件从DOM中删除
卸载阶段的生命周期函数只有一个,即componentWillUnmount
该方法用于监听组件即将卸载,通常用于在组件卸载时,删除掉一些组件加在全局中的内容
再附上三个版本的生命周期示图:
函数组件的生命周期
函数组件的是依赖于useEffectHooks API的,它相当于componentDidMount、componentDidUpdate和componentWillUnmount三个Class钩子函数的结合体,具体生命周期如下:
组件挂载->执行副作用(回调函数)->组件更新->执行清理函数(返还函数)->执行副作用(回调函数)->组件准备卸载->执行清理函数(返还函数)->组件卸载
如果单纯的想要在组件挂载、更新、卸载阶段执行
- useEffect(callback, [])依赖参数置空是componentDidMount和componentWillUnmount
- useEffect(callback, [args])依赖参数不为空,还要借助useRef Hooks比较前后依赖数据实现componentDidUpdate