React生命周期

491 阅读4分钟

React V16.3版本之前

一、组件挂载时

  1. constructor

    constructor(props) {
        super(props)
        this.state = {}
    }
    
    • 初始化state
    • 进行方法绑定
    • 不可调用setState()
  2. componentWillMount

    • 在render(挂载)之前被调用,因此在此生命周期函数中调用setState不会重新渲染
    • 避免在此方法中引入任何副作用;(百度说:如果ajax请求过来数据为空,会影响页面渲染,使页面空白。另外在同构的情况下,在此生命周期中使用ajax会出错)
    • 服务端渲染唯一会调用的生命周期函数
  3. render()

  4. componentDidMount

    • 在render(挂载)之后立即调用
    • 依赖DOM节点的初始化,实例化网络数据请求等具有副作用的可以放在这里
    • 直接调用setState会出发额外渲染但此渲染发生在浏览器更新屏幕之前,即使两次调用render的情况用户也不会看见中间状态,但是这样会导致新能问题

二、本组件更新时

  1. shuldComponentUpdate(nextProps,nextState)

    shuldComponentUpdate(nextProps,nextState) {
        return this.state.xxx !== nextState.xxx || this.props.xxx !== nextProps.xxx
    }
    
    • 首次渲染或者使用forceupdate()时不会调用,当props或state发生变化时,它会在渲染执行前被调用,返回默认值为true

    • 如果一定要手动编写此函数,可以将this.propsnextProps以及this.statenextState进行比较,并返回false跳过更新。返回false并不能阻止子组件在自己的state更改时重新渲染

    • 不建议在此声明周期方法中进行深比较或使用JSON.stringfy(),这样非常非常影响效率且损害性能。

    • 此方法作为性能优化方式存在,不要企图依靠此方法来阻止渲染,建议使用内置的PurComponent组件而不是使用手动编写此生命周期函数。PurComponent会对propsstate进行浅比较并减少跳过必要更新的可能性

  2. componentWillUpate(nextProps, nextState)

    • 当组件收到新的props或state时,在渲染之前调用,在更新之前做更新准备
    • 此方法中不可执行setState()方法及其它可能触发组件更新的操作
  3. render()

  4. componentDidUpdate(prevProps, prevState, snapshot)

        componentDidUpdate(prevProps) {
          // 典型用法(不要忘记比较 props):
          if (this.props.userID !== prevProps.userID) {
            this.fetchData(this.props.userID);
          }
        }
    
    • 会在更新后立即调用,首次渲染不会调用
    • 可以进行具有副作用的操作,比如更新操作或者网络数据请求
    • 如果调用setState()方法,必须放在一个条件语句里边,否则会造成死循环
    • 它还会导致额外的重新渲染,虽然用户不可见,但会影响组件性能
    • 不能直接将props镜像给state请考虑直接使用props
    • 如果组件实现了 getSnapshotBeforeUpdate() 生命周期(不常用),则它的返回值将作为 componentDidUpdate() 的第三个参数 “snapshot” 参数传递。否则此参数将为 undefined

三、父组件更新props改变时

  1. componentWillReceiveProps(nextProps)

    componentWillReceiveProps(nextProps) {
        if(this.props.xxx === nextProps.xxx) xxx
    }
    
    • 会在 已挂载 的组件接收新的 props 之前被调用
    • 如果你需要在props发生变化(或者说新传入的props)来更新state,你可能需要比较this.propsnextProps, 然后使用this.setState()方法来改变this.state
    • 如果父组件导致组件重新渲染,即使props没有更改,也会调用此方法。如果只想处理更改,请确保进行当前值与变更值的比较
    • setState() 方法不会触发此方法。

    这里特殊说明一下这个生命周期的一个使用场景

    例如这个右边的单行栏一般是个组件它的导航高亮需要根据路由而定,所以代码逻辑一般是如下

    componentWillReceiveProps(nextProps) {
        if(this.props.router.location.pathname !== nextProps.router.location.pathname) {
            // 这里去做setState操作去更新导航栏子组件的UI
            this.setState({})
        }
    }
    

四、组件卸载

  1. componentWillUnmount()

    • 组件卸载做清除操作

React V16.3版本之后

1. static getDerivedStateFromProps(props, state)

  • getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用(在每次渲染前都会触发此方法)。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容

  • getDerivedStateFromProps 的存在只有一个目的:让组件在 props 变化时更新 state

    需要考虑的问题

2. getSnapshotBeforeUpdate(prevProps, prevState)

  • getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()。