16.3 新版react生命周期 图示

16.3 新版react生命周期

React v16.0前的生命周期

其实大部分团队不见得会跟进升到16版本,因此16前的生命周期仍是颇有必要掌握的,况且16也是基于以前的修改html

img

第一个是组件初始化(initialization)阶段

也就是如下代码中类的构造方法( constructor() ),Test类继承了react Component这个基类,也就继承这个react的基类,才能有render(),生命周期等方法可使用,这也说明为何函数组件不能使用这些方法的缘由。react

super(props)用来调用基类的构造方法( constructor() ), 也将父组件的props注入给子组件,功子组件读取(组件中props只读不可变,state可变)。
constructor()用来作一些组件的初始化工做,如定义this.state的初始内容。segmentfault

import React, { Component } from 'react';

class Test extends Component {
  constructor(props) {
    super(props);
  }
}

第二个是组件的挂载(Mounting)阶段

此阶段分为componentWillMount,render,componentDidMount三个时期。

  • componentWillMount:

在组件挂载到DOM前调用,且只会被调用一次,在这边调用this.setState不会引发组件从新渲染,也能够把写在这边的内容提早到constructor()中,因此项目中不多用。数组

  • render:

根据组件的props和state(无二者的重传递和重赋值,论值是否有变化,均可以引发组件从新render) ,return 一个React元素(描述组件,即UI),不负责组件实际渲染工做,以后由React自身根据此元素去渲染出页面DOM。render是纯函数(Pure function:函数的返回结果只依赖于它的参数;函数执行过程里面没有反作用),不能在里面执行this.setState,会有改变组件状态的反作用。服务器

  • componentDidMount:

组件挂载到DOM后调用,且只会被调用一次async

第三个是组件的更新(update)阶段

在讲述此阶段前须要先明确下react组件更新机制。setState引发的state更新或父组件从新render引发的props更新,更新后的state和props相对以前不管是否有变化,都将引发子组件的从新render。详细可看这篇文章函数

形成组件更新有两类(三种)状况:

  • 1.父组件从新render

父组件从新render引发子组件从新render的状况有两种,内容及代码修引自xiaoyann的回答性能

a. 直接使用,每当父组件从新render致使的重传props,子组件将直接跟着从新渲染,不管props是否有变化。可经过shouldComponentUpdate方法优化。优化

class Child extends Component {
   shouldComponentUpdate(nextProps){ // 应该使用这个方法,不然不管props是否有变化都将会致使组件跟着从新渲染
        if(nextProps.someThings === this.props.someThings){
          return false
        }
    }
    render() {
        return <div>{this.props.someThings}</div>
    }
}

b.在componentWillReceiveProps方法中,将props转换成本身的statethis

class Child extends Component {
    constructor(props) {
        super(props);
        this.state = {
            someThings: props.someThings
        };
    }
    componentWillReceiveProps(nextProps) { // 父组件重传props时就会调用这个方法
        this.setState({someThings: nextProps.someThings});
    }
    render() {
        return <div>{this.state.someThings}</div>
    }
}

根据官网的描述

在该函数(componentWillReceiveProps)中调用 this.setState() 将不会引发第二次渲染。

是由于componentWillReceiveProps中判断props是否变化了,若变化了,this.setState将引发state变化,从而引发render,此时就不必再作第二次因重传props引发的render了,否则重复作同样的渲染了。

  • 2.组件自己调用setState,不管state有没有变化。可经过shouldComponentUpdate方法优化。
class Child extends Component {
   constructor(props) {
        super(props);
        this.state = {
          someThings:1
        }
   }
   shouldComponentUpdate(nextStates){ // 应该使用这个方法,不然不管state是否有变化都将会致使组件从新渲染
        if(nextStates.someThings === this.state.someThings){
          return false
        }
    }

   handleClick = () => { // 虽然调用了setState ,但state并没有变化
        const preSomeThings = this.state.someThings
         this.setState({
            someThings: preSomeThings
         })
   }

    render() {
        return <div onClick = {this.handleClick}>{this.state.someThings}</div>
    }
}

此阶段分为componentWillReceiveProps,shouldComponentUpdate,componentWillUpdate,render,componentDidUpdate

  • componentWillReceiveProps(nextProps)

此方法只调用于props引发的组件更新过程当中,参数nextProps是父组件传给当前组件的新props。但父组件render方法的调用不能保证重传给当前组件的props是有变化的,因此在此方法中根据nextProps和this.props来查明重传的props是否改变,以及若是改变了要执行啥,好比根据新的props调用this.setState出发当前组件的从新render

  • shouldComponentUpdate(nextProps, nextState)

此方法经过比较nextProps,nextState及当前组件的this.props,this.state,返回true时当前组件将继续执行更新过程,返回false则当前组件更新中止,以此可用来减小组件的没必要要渲染,优化组件性能。

ps:这边也能够看出,就算componentWillReceiveProps()中执行了this.setState,更新了state,但在render前(如shouldComponentUpdate,componentWillUpdate),this.state依然指向更新前的state,否则nextState及当前组件的this.state的对比就一直是true了。

  • componentWillUpdate(nextProps, nextState)

此方法在调用render方法前执行,在这边可执行一些组件更新发生前的工做,通常较少用。

  • render

render方法在上文讲过,这边只是从新调用。

  • componentDidUpdate(prevProps, prevState)

此方法在组件更新后被调用,能够操做组件更新的DOM,prevProps和prevState这两个参数指的是组件更新前的props和state

卸载阶段

此阶段只有一个生命周期方法:componentWillUnmount

  • componentWillUnmount

此方法在组件被卸载前调用,能够在这里执行一些清理工做,好比清楚组件中使用的定时器,清楚componentDidMount中手动建立的DOM元素等,以免引发内存泄漏。

React v16.4 的生命周期

React v16.4 的生命周期图

img

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,大改动来了,引入了两个新的生命周期函数。

新引入了两个新的生命周期函数:getDerivedStateFromPropsgetSnapshotBeforeUpdate

getDerivedStateFromProps

getDerivedStateFromProps原本(React v16.3中)是只在建立和更新(由父组件引起部分),也就是否是不禁父组件引起,那么getDerivedStateFromProps也不会被调用,如自身setState引起或者forceUpdate引起。

React v16.3 的生命周期图

img

React v16.3

这样的话理解起来有点乱,在React v16.4中改正了这一点,让getDerivedStateFromProps不管是Mounting仍是Updating,也不管是由于什么引发的Updating,所有都会被调用,具体可看React v16.4 的生命周期图。

React v16.4后的getDerivedStateFromProps

static getDerivedStateFromProps(props, state) 在组件建立时和更新时的render方法以前调用,它应该返回一个对象来更新状态,或者返回null来不更新任何内容。

getSnapshotBeforeUpdate

getSnapshotBeforeUpdate() 被调用于render以后,能够读取但没法使用DOM的时候。它使您的组件能够在可能更改以前从DOM捕获一些信息(例如滚动位置)。今生命周期返回的任何值都将做为参数传递给componentDidUpdate()。

官网给的例子:

class ScrollingList extends React.Component {
  constructor(props) {
    super(props);
    this.listRef = React.createRef();
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    //咱们是否要添加新的 items 到列表?
    // 捕捉滚动位置,以便咱们能够稍后调整滚动.
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    //若是咱们有snapshot值, 咱们已经添加了 新的items.
    // 调整滚动以致于这些新的items 不会将旧items推出视图。
    // (这边的snapshot是 getSnapshotBeforeUpdate方法的返回值)
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      <div ref={this.listRef}>{/* ...contents... */}</div>
    );
  }
}
相关文章
相关标签/搜索