概述
前几天和同事讨论react,发现对生命周期还是了解的不够深入,于是今天翻看了react关于生命周期的官方文档,刚好发现react发布了新版本,并且对生命周期做了修改,于是认真阅读了一下,并记录下来,供以后开发时参考,相信对其他人也有用。
总述
以前觉得生命周期的英文太多了,要记很麻烦。现在看文档才发现,有些小窍门。
带有Will的都是在动作发生前执行,带有Did的都是在动作发生之后执行。然后再记住几个关键词:mounting,updating,unmounting,error handling。
旧的生命周期
Mounting(加载阶段:涉及6个钩子函数)
constructor()
加载的时候调用一次,可以初始化state
getDefaultProps()
设置默认的props,也可以用dufaultProps设置组件的默认属性。
getInitialState()
初始化state,可以直接在constructor中定义this.state
componentWillMount()
组件加载时只调用,以后组件更新不调用,整个生命周期只调用一次,此时可以修改state
render()
react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行
componentDidMount()
组件渲染之后调用,只调用一次
Updating(更新阶段:涉及5个钩子函数)
componentWillReceiveProps(nextProps)
组件加载时不调用,组件接受新的props时调用
shouldComponentUpdate(nextProps, nextState)
组件接收到新的props或者state时调用,return true就会更新dom(使用diff算法更新),return false能阻止更新(不调用render)
componentWillUpdata(nextProps, nextState)
组件加载时不调用,只有在组件将要更新时才调用,此时可以修改state
render()
react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行
componentDidUpdate()
组件加载时不调用,组件更新完成后调用
Unmounting(卸载阶段:涉及1个钩子函数)
componentWillUnmount()
组件渲染之后调用,只调用一次
组件的基本写法
import React, { Component } from 'react'
export default class OldReactComponent extends Component {
constructor(props) {
super(props)
// getDefaultProps:接收初始props
// getInitialState:初始化state
}
state = {
}
componentWillMount() { // 组件挂载前触发
}
render() {
return (
<h2>Old React.Component</h2>
)
}
componentDidMount() { // 组件挂载后触发
}
componentWillReceiveProps(nextProps) { // 接收到新的props时触发
}
shouldComponentUpdate(nextProps, nextState) { // 组件Props或者state改变时触发,true:更新,false:不更新
return true
}
componentWillUpdate(nextProps, nextState) { // 组件更新前触发
}
componentDidUpdate() { // 组件更新后触发
}
componentWillUnmount() { // 组件卸载时触发
}
}
新的生命周期
Mounting(加载阶段:涉及4个钩子函数)
constructor()
加载的时候调用一次,可以初始化state
static getDerivedStateFromProps(props, state)
组件每次被rerender的时候,包括在组件构建之后(虚拟dom之后,实际dom挂载之前),每次获取新的props或state之后;每次接收新的props之后都会返回一个对象作为新的state,返回null则说明不需要更新state;配合componentDidUpdate,可以覆盖componentWillReceiveProps的所有用法
render()
react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行
componentDidMount()
组件渲染之后调用,只调用一次
Updating(更新阶段:涉及5个钩子函数)
static getDerivedStateFromProps(props, state)
组件每次被rerender的时候,包括在组件构建之后(虚拟dom之后,实际dom挂载之前),每次获取新的props或state之后;每次接收新的props之后都会返回一个对象作为新的state,返回null则说明不需要更新state;配合componentDidUpdate,可以覆盖componentWillReceiveProps的所有用法
shouldComponentUpdate(nextProps, nextState)
组件接收到新的props或者state时调用,return true就会更新dom(使用diff算法更新),return false能阻止更新(不调用render)
render()
react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行
getSnapshotBeforeUpdate(prevProps, prevState)
触发时间: update发生的时候,在render之后,在组件dom渲染之前;返回一个值,作为componentDidUpdate的第三个参数;配合componentDidUpdate, 可以覆盖componentWillUpdate的所有用法
componentDidUpdate()
组件加载时不调用,组件更新完成后调用
Unmounting(卸载阶段:涉及1个钩子函数)
组件渲染之后调用,只调用一次
Error Handling(错误处理)
componentDidCatch(error,info)
任何一处的javascript报错会触发
组件的基本写法:
import React, { Component } from 'react'
export default class NewReactComponent extends Component {
constructor(props) {
super(props)
// getDefaultProps:接收初始props
// getInitialState:初始化state
}
state = {
}
static getDerivedStateFromProps(props, state) { // 组件每次被rerender的时候,包括在组件构建之后(虚拟dom之后,实际dom挂载之前),每次获取新的props或state之后;;每次接收新的props之后都会返回一个对象作为新的state,返回null则说明不需要更新state
return state
}
componentDidCatch(error, info) { // 获取到javascript错误
}
render() {
return (
<h2>New React.Component</h2>
)
}
componentDidMount() { // 挂载后
}
shouldComponentUpdate(nextProps, nextState) { // 组件Props或者state改变时触发,true:更新,false:不更新
return true
}
getSnapshotBeforeUpdate(prevProps, prevState) { // 组件更新前触发
}
componentDidUpdate() { // 组件更新后触发
}
componentWillUnmount() { // 组件卸载时触发
}
}
总结:
- React16新的生命周期弃用了componentWillMount、componentWillReceiveProps,componentWillUpdate
- 新增了getDerivedStateFromProps、getSnapshotBeforeUpdate来代替弃用的三个钩子函数(componentWillMount、componentWillReceiveProps,componentWillUpdate)
- React16并没有删除这三个钩子函数,但是不能和新增的钩子函数(getDerivedStateFromProps、getSnapshotBeforeUpdate)混用,React17将会删除componentWillMount、componentWillReceiveProps,componentWillUpdate
- 新增了对错误的处理(componentDidCatch)
React v16.4+ 的生命周期
变更缘由
原来(React v16.0前)的生命周期在React v16推出的Fiber之后就不合适了,因为如果要开启async rendering,在render函数之前的所有函数,都有可能被执行多次。
原来(React v16.0前)的生命周期有哪些是在render前执行的呢?
- componentWillMount
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
如果开发者开了async rendering,而且又在以上这些render前执行的生命周期方法做AJAX请求的话,那AJAX将被无谓地多次调用。。。明显不是我们期望的结果。而且在componentWillMount里发起AJAX,不管多快得到结果也赶不上首次render,而且componentWillMount在服务器端渲染也会被调用到(当然,也许这是预期的结果),这样的IO操作放在componentDidMount里更合适。
禁止不能用比劝导开发者不要这样用的效果更好,所以除了shouldComponentUpdate,其他在render函数之前的所有函数(componentWillMount,componentWillReceiveProps,componentWillUpdate)都被getDerivedStateFromProps替代。
也就是用一个静态函数getDerivedStateFromProps来取代被deprecate的几个生命周期函数,就是强制开发者在render之前只做无副作用的操作,而且能做的操作局限在根据props和state决定新的state
React v16.0刚推出的时候,是增加了一个componentDidCatch生命周期函数,这只是一个增量式修改,完全不影响原有生命周期函数;但是,到了React v16.3,大改动来了,引入了两个新的生命周期函数: getDerivedStateFromProps
,getSnapshotBeforeUpdate
getDerivedStateFromProps
getDerivedStateFromProps
本来(React v16.3中)是只在创建和更新(由父组件引发部分)中调用。如果不是由父组件引发,那么getDerivedStateFromProps也不会被调用,如自身setState引发或者forceUpdate引发。
getSnapshotBeforeUpdate()
getSnapshotBeforeUpdate() 被调用于render之后,可以读取但无法使用DOM的时候。它使您的组件可以在可能更改之前从DOM捕获一些信息(例如滚动位置)。此生命周期返回的任何值都将作为参数传递给componentDidUpdate()。