react生命周期-比较

400 阅读3分钟

新老版本生命周期说明

老版react生命周期函数

新版react生命周期函数

老版的react生命周期非常对称,但终究是有一些问题的,所以推出了getDerivedStateFromProps,去了一组生命周期API:

  • componentWillReceiveProps
  • componentWillMount
  • componentWillUpdate

可以看到除了shouldComponentUpdate,render之前的所有生命周期函数全灭。

render之后还引入了一个新的声明周期函数getSnapshotBeforeUpdate,该函数会在render之后执行,而执行之时DOM元素还没有被更新,给了一个机会去获取DOM信息,计算得到一个snapshot,这个snapshot会作为componentDidUpdate的第三个参数传入。

老版react生命周期函数:

初始化阶段:
    getDefaultProps:获取实例的默认属性
    getInitialState:获取每个实例的初始化状态
    componentWillMount:组件即将被装载、渲染到页面上
    render:组件在这里生成虚拟的 DOM 节点
    componentDidMount:组件真正在被装载之后

运行中状态:
    componentWillReceiveProps:组件将要接收到属性的时候调用
    shouldComponentUpdate:组件接受到新属性或者新状态的时候(可以返回 false,接收数据后不更新,阻止 render 调用,后面的函数不会被继续执行了)
    componentWillUpdate:组件即将更新不能修改属性和状态
    render:组件重新描绘
    componentDidUpdate:组件已经更新

销毁阶段:
    componentWillUnmount:组件即将销毁

新版react生命周期函数:

初始化阶段:
    getDefaultProps:获取实例的默认属性
    getInitialState:获取每个实例的初始化状态
    getDerivedStateFromProps:纯函数,将props映射到state
    render:组件在这里生成虚拟的 DOM 节点
    componentDidMount:组件真正在被装载之后(在这里获取数据)

运行中状态:
    getDerivedStateFromProps:纯函数,将props映射到state
    shouldComponentUpdate:组件接受到新属性或者新状态的时候(可以返回 false,接收数据后不更新,阻止 render 调用,后面的函数不会被继续执行了)
    render:组件重新描绘
    getSnapshotBeforeUpdate:在最终确定的render执行之前执行,保证其获取到的元素状态与didUpdate中获取到的元素状态相同
    componentDidUpdate:组件已经更新

销毁阶段:
    componentWillUnmount:组件即将销毁

说明:

getDerivedStateFromProps

getDerivedStateFromProps的作用是将传入的props映射到state,可以改变状态。

它还是一个静态函数,里面不能使用this,也就是所谓的纯函数,防止了开发者在这里书写有副作用的代码,而且开发者只能通过prevState而不是prevProps来做对比,保证了state和props之间的简单关系以及不需要处理第一次渲染时prevProps为空的情况。

getSnapshotBeforeUpdate

getSnapshotBeforeUpdate:在最终确定的render执行之前执行,保证其获取到的元素状态与didUpdate中获取到的元素状态相同。

官网给了一个例子,是用getSnapshotBeforeUpdate处理scroll

大概是这样:

import React from "react"
import ReactDOM from "react-dom"
class News extends React.Component{
    constructor(props){
        super(props)
        this.scrollRef = React.createRef();
    }
    state = {
        // news:["news6","news5","new4","news3","news2","new1"]
        news:[]
    }
    componentDidMount(){
        this.timer = setInterval(()=>{
            this.setState({
                news:[`${this.state.news.length}`,...this.state.news]
            })
        },1000)
    }
    componentWillUnmount(){
        clearInterval(this.timer)
    }
    // 获取更新之前dom的快照
    getSnapshotBeforeUpdate(){
        // console.log(this.scrollRef.current.scrollHeight)
        // 在getSnapshotBeforeUpdate中返回了一个值,这个值会给componedDidUpdate的最后一个参数
        return this.scrollRef.current.scrollHeight;
    }
    componentDidUpdate(prevProps,prevState,lastScrollHeight){
        // console.log(lastScrollHeight)
        // console.log(this.scrollRef.current.scrollTop)  // 0
        let scrollTop = this.scrollRef.current.scrollTop; 
        this.scrollRef.current.scrollTop = scrollTop+(this.scrollRef.current.scrollHeight-lastScrollHeight)
    }
    render(){
        let styles = {
            height:"100px",
            width:"200px",
            border:"1px solid red",
            overflow:"auto"
        }
        return(
            <ul style={styles} ref={this.scrollRef}>
               {
                   this.state.news.map((item,index)=><li key={index}>{item}</li>)
               }
            </ul>
        )
    }
}
ReactDOM.render(<News />, window.app)

参考文章: juejin.cn/post/684490… zhuanlan.zhihu.com/p/38030418