一、旧版:
1、initialization
初始化属性和状态
2、Mounting (加载阶段:涉及3个钩子函数)
2.1 componentWillMount()
组件加载时只调用,以后组件更新不调用,整个生命周期只调用一次,此时可以修改state
2.2 render()
react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行
2.3 componentDidMount()
组件渲染之后调用,只调用一次
3、Updating(更新阶段:涉及5个钩子函数)
3.1 componentWillReceivePorps(nextProps)
组件加载时不调用,组件接受新的props时调用
3.2 shouldComponentUpdate(nextProps, nextState)
组件接收到新的props或者state时调用,return true就会更新dom(使用diff算法更新),return false能阻止更新(不调用render)
3.3 componentWillUpdata(nextProps, nextState)
组件加载时不调用,只有在组件将要更新时才调用,此时可以修改state
3.4 render()
react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行
3.5 componentDidUpdate()
组件加载时不调用,组件更新完成后调用
4、Unmounting(卸载阶段:涉及1个钩子函数)
4.1 componentWillUnmount()
组件渲染之后调用,只调用一次
基本用法:
import React from "react";
import ReactDOM from "react-dom";
/**
* 只有类组件才有生命周期
*
*/
class App extends React.Component{
static defaultProps = { //设置默认属性
name:'leah'
}
constructor(props) {
super(props)
this.state = {count: 0}
console.log('1.执行构造函数,设置初始状态')
}
//1.挂载
componentWillMount(){
console.log('1.1组件将要挂载到页面上')
}
handleClick = () =>{
this.setState({count: this.state.count +1})
}
render() {
console.log('1.2.返回虚拟dom')
return (
<div>
<p>{this.state.count}</p>
<button onClick={this.handleClick}>+</button>
{/* <ChildCounter count={this.state.count}></ChildCounter> */
this.state.count < 3 ? <ChildCounter count={this.state.count}></ChildCounter> : null //当count>3的时候讲子组件销毁
}
</div>
)
}
//当虚拟dom被挂载到真实dom上之后才执行这个,这个时候才能获取到真实dom
componentDidMount(){
console.log('1.3.组件已经挂载到了页面上')
}
//2.更新
//2.1询问组件状态是否更新
shouldComponentUpdate(nextprops,nextState){
console.log('2.1 询问组件状态是否更新')
// return nextState.count % 3 === 0 //表示如果state是3的倍数就更新,否则就不更新
return true
}
componentWillUpdate(){
console.log('2.2组件状态将要更新')
}
componentDidUpdate(){
console.log('2.2组件状态已经更新')
}
}
class ChildCounter extends React.Component{
componentWillReceiveProps(newprops){ //组件属性的更新多了这一步
console.log('组件将要接收新的属性',newprops)
}
shouldComponentUpdate(nextprops,nextState){
console.log('询问子组件属性是否更新')
// return nextprops.count % 6 === 0 //表示如果state是3的倍数就更新,否则就不更新
return true
}
componentWillUpdate(){
console.log('子组件属性将要更新')
}
componentDidUpdate(){
console.log('子组件属性已经更新')
}
componentWillUnmount(){
console.log('子组件将要被销毁')
}
render(){
console.log('childCounter render')
return(
<div>{this.props.count}</div>
)
}
}
ReactDOM.render(<App></App>,document.getElementById('root'))
/**
* componentWillMount 先父后子
* componentDidMount 先子后父
*/
二、新版生命周期
1、 Mounting(加载阶段:涉及4个钩子函数)
1.1 constructor()
加载的时候调用一次,可以初始化state
1.2 static getDerivedStateFromProps(props, state)
组件每次被rerender的时候,包括在组件构建之后(虚拟dom之后,实际dom挂载之前),每次获取新的props或state之后;每次接收新的props之后都会返回一个对象作为新的state,返回null则说明不需要更新state;
配合componentDidUpdate,可以覆盖componentWillReceiveProps的所有用法
1.3 render()
react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行
1.4 componentDidMount()
组件渲染之后调用,只调用一次
2、Updating(更新阶段:涉及5个钩子函数)
2.1 static getDerivedStateFromProps(props, state)
组件每次被rerender的时候,包括在组件构建之后(虚拟dom之后,实际dom挂载之前),每次获取新的props或state之后;每次接收新的props之后都会返回一个对象作为新的state,返回null则说明不需要更新state;配合componentDidUpdate,可以覆盖componentWillReceiveProps的所有用法
2.2 shouldComponentUpdate(nextProps, nextState)
组件接收到新的props或者state时调用,return true就会更新dom(使用diff算法更新),return false能阻止更新(不调用render)
2.3 render()
react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行
2.4 getSnapshotBeforeUpdate(prevProps, prevState)
触发时间: update发生的时候,在render之后,在组件dom渲染之前;返回一个值,作为componentDidUpdate的第三个参数;配合componentDidUpdate, 可以覆盖componentWillUpdate的所有用法
2.5 componentDidUpdate()
组件加载时不调用,组件更新完成后调用
3、Unmounting(卸载阶段:涉及1个钩子函数)
3.1 componentWillUnmount()
组件渲染之后调用,只调用一次
基本用法:
import React from "react";
import ReactDOM from "react-dom";
/**
* 新的生命周期函数去掉了三个:
* componentWillReceiveProps componentWillUpdate componentWillMount
* 多了两个:getDerivedStateFromProps
*
*/
class App extends React.Component{
static defaultProps = { //设置默认属性
name:'leah'
}
constructor(props) {
super(props)
this.state = {count: 0}
console.log('1.执行构造函数,设置初始状态')
}
//1.挂载
handleClick = () =>{
this.setState({count: this.state.count +1})
}
render() {
console.log('1.2.返回虚拟dom')
return (
<div>
<p>{this.state.count}</p>
<button onClick={this.handleClick}>+</button>
<ChildCounter count={this.state.count}></ChildCounter>
</div>
)
}
//当虚拟dom被挂载到真实dom上之后才执行这个,这个时候才能获取到真实dom
componentDidMount(){
console.log('1.3.组件已经挂载到了页面上')
}
//2.更新
//2.1询问组件状态是否更新
shouldComponentUpdate(nextprops,nextState){
console.log('2.1 询问组件状态是否更新')
// return nextState.count % 3 === 0 //表示如果state是3的倍数就更新,否则就不更新
return true
}
componentDidUpdate(){
console.log('2.2组件状态已经更新')
}
}
class ChildCounter extends React.Component{
state = {name: 'leah', count: 0}
shouldComponentUpdate(nextprops,nextState){
console.log('询问子组件属性是否更新')
// return nextprops.count % 6 === 0 //表示如果state是3的倍数就更新,否则就不更新
return true
}
componentDidUpdate(){
console.log('子组件属性已经更新')
}
componentWillUnmount(){
console.log('子组件将要被销毁')
}
//每当状态属性变更的时候执行此方法,可以得到最新的属性和状态
//nextProps 代表新的属性对象 prevState 代表旧的状态对象
static getDerivedStateFromProps(nextProps, prevState){
if( nextProps.count % 2 === 0) {
return {count : nextProps.count * 2}
}else {
return {count : nextProps.count * 3}
}
}
render(){
console.log('childCounter render')
return(
<div>{this.state.count}</div>
)
}
}
ReactDOM.render(<App></App>,document.getElementById('root'))
/**
* componentWillMount 先父后子
* componentDidMount 先子后父
*/
总结:
- React16新的生命周期弃用了componentWillMount、componentWillReceivePorps,componentWillUpdate
- 新增了getDerivedStateFromProps、getSnapshotBeforeUpdate来代替弃用的三个钩子函数(componentWillMount、componentWillReceivePorps,componentWillUpdate)
- React16并没有删除这三个钩子函数,但是不能和新增的钩子函数(getDerivedStateFromProps、getSnapshotBeforeUpdate)混用,React17将会删除componentWillMount、componentWillReceivePorps,componentWillUpdate
- 新增了对错误的处理(componentDidCatch)
https://zhuanlan.zhihu.com/p/38030418 这篇文章有点内容