React生命周期

前言

若是将组件比做咱们图中的🐜,吊绳比做🐜(组件)的寿命,吊绳左端表示🐜的出生(组件的建立),右端表示🐜的死亡(组件的销毁)。🐜从生到死的过程会触发吊牌上的钩子函数执行,在React中咱们把组件从建立到销毁的过程当中须要触发的钩子函数称之为生命周期函数react

React生命周期

旧版

初始化阶段(Initalization)

  • setup props ande state(设置组件的初始化属性和状态)

初始化状态对象

static defaultProps = {
    name:'计数器'  //初始化默认的属性对象
}
复制代码

初始化属性对象

constructor(props){
    super(props);
    this.state = {
        number:0
    }
}
复制代码

挂载阶段(Mounting)

挂载:将虚拟DOM转化为真实DOM的过程ajax

componentWillMount

组件挂载以前,在渲染过程当中可能会执行屡次,不推荐使用浏览器

render

组件挂载架构

componentDidMount

组件挂载以后,永远只会执行一次,推荐在此阶段执行反作用,进行异步操做。好比发ajax请求,操做DOMapp

更新阶段(Updation)

属性更新(props变化)

componentWillReceiveProps

组件收到新的属性对象时调用,首次渲染不会触发异步

shouldComponentUpdate

询问组件是否能够更新函数

  • 参数:新的属性对象
  • 返回:boolean
    • true容许更新继续向下执行
    • false不容许更新,中止执行,不会调用以后的生命周期函数
componentWillUpdate

组件更新以前测试

render

根据新的属性对象从新挂载(渲染)组件ui

componentDidUpdate

组件更新完成this

状态更新(state变化)

shouldComponentUpdate

询问组件是否能够更新

  • 参数:新的状态对象
  • 返回:boolean
    • true容许更新继续向下执行
    • false不容许更新,中止执行,不会调用以后的生命周期函数
componentWillUpdate

组件更新以前

render

根据新的状态对象从新挂载(渲染)组件

componentDilUpdtae

组件更新完成

卸载阶段(Unmounting)

componentWillUnmount

组件卸载以前调用

放码过来

有兴趣的朋友能够根据如下代码进行测试

import React, { Component } from 'react';
/** * 父组件 */
class Counter extends Component {
  static defaultProps = { //初始化默认的属性对象
    name:'计数器'
  }
  constructor(props) {
    super(props);
    this.state = { // 初始化默认的状态对象
      number:0
    }
    console.log('1. 父constructor初始化 props and state');
  }
  componentWillMount() {
    console.log('2. 父componentWillMount组件将要挂载');
  }
  componentDidMount() {
    console.log('4. 父componentDidMount组件挂载完成');
  }
  shouldComponentUpdate() {
    console.log('5. 父componentShouldUpdate询问组件是否能够更新');
    return true;
  }
  componentWillUpdate() {
    console.log('6. 父componentWillUpdate组件将要更新');
  }
  componentDidUpdate() {
    console.log('7. 父componentDidUpdate组件更新完成');
  }
  render() {
    console.log('3. 父render渲染,也就是挂载');
    const style = {display:'block'}
    return (
      <div style={{border:'10px solid green',pending:'10px'}}> {this.props.name}:{this.state.number} <button onClick={this.add} style={style}>+</button> {this.state.number %3 !== 0 && <SubCounter number={this.state.number}/>} </div> ); } add = () => { this.setState({ number:this.state.number+1 }) } } /** * 子组件 */ class SubCounter extends Component { static defaultProps = { number:10 } componentWillReceiveProps() { console.log('1. 子componentWillReceiveProps属性将要发生变化 '); } shouldComponentUpdate(nextProps, nextState) { console.log('2. 子componentShouldUpdate询问组件是否能够更新'); // 调用此方法的时候会把新的属性对象和新的状态对象传递过来 if (nextProps.number % 3 === 0) { return true; } return false; } componentWillUnmount() { console.log(' 3.子componentWillUnmount组件将要卸载 '); } render() { return ( <div style={{border:'10px solid red'}}> {this.props.number} </div> ); } } export default Counter; 复制代码

新版

建立时

constructor

初始化属性和状态

getDerivedStateFromProps

根据属性对象派生状态对象

  • 静态方法
  • 参数:新的属性对象,旧的状态对象
  • 用途:在没有这个生命周期函数以前,咱们使用的数据来源多是属性对象,也多是状态对象,在咱们的上文中的放码过来阶段就有所体现,咱们能够经过这个生命周期函数将属性对象派生到状态对象上,使咱们在代码中只经过this.state.XXX来绑定咱们的数据。示例以下
import React, { Component } from 'react';
/** * 父 */
class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      number:0
    }
  }
  render() {
    return (
      <div> <p>{this.state.number}</p> <button onClick={this.add}>+</button> <SubCounter number={this.state.number}/> </div> ); } add = () => { this.setState({ number:this.state.number+1 }) } } /** * 子 */ class SubCounter extends Component { constructor(props) { super(props); this.state = { number:0 } } static getDerivedStateFromProps(nextProps, prevState) { if (nextProps.number % 2 === 0) { return {number:nextProps.number*2} } else { return {number:nextProps.number*3} } } render() { console.log(this.state); return ( <div> <p>{this.state.number}</p> </div> ); } } export default Counter; 复制代码

render

挂载(渲染)组件

componentDidMount

组件挂载(渲染)完成

更新时

getDerivedStateFromProps

根据属性对象派生状态对象

  • 静态方法
  • 参数:新的属性对象,旧的状态对象

shouldComponentUpdate

询问组件是否能够更新

  • 参数:新的状态对象
  • 返回:boolean
    • true容许更新继续向下执行
    • false不容许更新,中止执行,不会调用以后的生命周期函数

render

根据新的状态对象从新挂载(渲染)组件

getSnapshotbeforeUpdate

获取更新前的快照

  • 举例:在咱们的平常开发中你必定会遇到这个问题,异步加载资源,当浏览器处于非第一屏的时候而且所在屏以前的模块并无加载出来,你确定不但愿在所在屏以前的模块加载出来以后浏览器显示窗口仍然处于当前的高度,而是但愿仍然处于咱们所浏览屏的高度,在没有这个生命周期以前react处理这个问题是很棘手的。

未使用getSnapshotbeforeUpdate

import React, { Component } from 'react';
class GetSnapshotBeforeUpdate extends Component {
  constructor(props) {
    super(props);
    this.wrapper = React.createRef();
    this.state = {
      messages:['4','3','2','1','0']
    }
  }
  componentDidMount() {
    setInterval(() => {
      this.setState(() => {
        this.state.messages.unshift(this.state.messages.length);
      }, () => {
          this.setState({
            messages: this.state.messages
          })
      })
    },1000)
  }
  render() {
    let style = {
      height: '100px',
      width: '200px',
      border: '1px solid red',
      overflow:'auto'
    }
    return (
      <ul style={style} ref={this.wrapper}> { this.state.messages.map((message, index) => <li key={index}>{message}</li>) } </ul>
    );
  }
}
export default GetSnapshotBeforeUpdate;
复制代码

使用getSnapshotbeforeUpdate

import React, { Component } from 'react';
class GetSnapshotBeforeUpdate extends Component {
  ...
  getSnapshotBeforeUpdate() {
    // 返回更新内容的高度
    return this.wrapper.current.scrollHeight;
  }
  // 组件更新完毕
  componentDidUpdate(prevProps,prevState,prevScrollHeight) {
    console.log(prevProps,prevState,prevScrollHeight);
    this.wrapper.current.scrollTop = this.wrapper.current.scrollTop +
    (this.wrapper.current.scrollHeight - prevScrollHeight);
  }
  ...
export default GetSnapshotBeforeUpdate;
复制代码

componentDidUpdate

组件更新完成

卸载时

componentWillUnmount

组件卸载以前

总结

数据获取为何必定要在componentDidMount里面调用

  • constructor
    • constructor()中获取数据的话,若是时间太长,或者出错,组件就渲染不出来,整个页面都无法渲染了

  • componentWillMount()
    • 【1】若是使用SSR(服务端渲染),componentWillMount会执行2次,一次在服务端,一次在客户端。而componentDidMount不会。

    • 【2】React16以后采用了Fiber架构,只有componentDidMount声明周期函数是肯定被执行一次的,相似componentWillMount的生命周期钩子都有可能执行屡次,因此不加以在这些生命周期中作有反作用的操做,好比请求数据之类

  • componentDidMount()
    • 【1】确保已经render过一次。提醒咱们正确地设置初始状态,这样就不会获得致使错误的undefined状态。

    • 【2】componentDidMount方法中的代码,是在组件已经彻底挂载到网页上才会调用被执行,因此能够保证数据的加载。此外,在这方法中调用setState方法,会触发重渲染。因此,官方设计这个方法就是用来加载外部数据用的,或处理其余的反作用代码。

新旧比较(废三增二)

  • 废弃了
    • componentWillMount
    • componentWillReceiveProps
    • componentWillUpdate
  • 增长了
    • getDerivedStateFromProps
    • getSnapshotbeforeUpdate
相关文章
相关标签/搜索