美文网首页React系列
第八节:React组件的生命周期

第八节:React组件的生命周期

作者: Dylan_Cao | 来源:发表于2022-06-27 20:29 被阅读0次

其实React组件并不是真正的DOM, 而是会生成JS对象的虚拟DOM, 虚拟DOM会经历创建,更新,删除的过程

这一个完整的过程就构成了组件的生命周期,React提供了钩子函数让我们可以在组件生命周期的不同阶段添加操作

1. 生命周期函数的理解

1.1 组件生命周期函数说明
  1. 组件生命周期函数主要分三类,组件的初始挂载,组件的更新渲染以及组件的卸载
  2. 有一些生命周期函数还在三个阶段都会执行的
1.2 组件的生命周期图
image

2. 生命周期函数

2.1 组件初始挂载
2.1.1 组件初始挂载生命周期函数认识

当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:

  1. constructor: 完成React数据的初始化
  2. conponentWillMount/UNSAFE_componentWillMonut: 页面渲染前调用(未来将废弃)
  3. render : class组件中唯一必须实现的方法,返回React元素渲染页面
  4. componentDidMount 页面初始化渲染完毕以后执行
2.1.2 constructor函数

说明:

  1. 如果不需要初始化state,或者不进行方法的绑定,则不需要实现constructor构造函数
  2. 在组件挂载前调用构造函数,如果继承React.Component,则必须调用super(props)
  3. constructor通常用于处理了state初始化和为事件处理函数绑定this实例
  4. 尽量避免将props外部数据赋值给组件内部state状态

注意: constructor 构造函数只在初始化化的时候执行一次

示例代码如下:

class MyCom extends React.Component{

    // 1\. constructor 构造函数
    constructor(props){
        super(props)
        console.log("组件初始化数据");
        // 初始化组件状态
        this.state = {
            count: 0
        }
        // 处理事件函数绑定组件实例
        this.handleClick = this.handleClick.bind(this)    
    }

    handleClick(){
        this.setState(() => ({
            count: ++ this.state.count
        }))

    }

    render(){
        return (
            <div>
                <p>点击次数{ this.state.count }</p>
                <button onClick={ this.handleClick }>点击</button>
            </div>
        )
    }
}

// 将组件渲染到页面上
ReactDOM.render(<MyCom/> ,document.getElementById("root"))

之前有讲过组件state也可以不定义在constructor构造函数中,事件函数也可以通过箭头函数处理this问题

因此如果不想使用constructor 也可以将两者移出

示例代码如下

class MyCom extends React.Component{

    // 初始化组件状态
    state = {
        count: 0
    }

    // 箭头函数处理this问题
    handleClick= ()=>{
        this.setState(() => ({
            count: ++ this.state.count
        }))
    }
   //... 
}

结果一样正常显示

2.1.3 componentWillMount函数

说明:

  1. componentWillMount生命周期函数在组件渲染前执行,
  2. 使用时函数能正常运行, 但是控制台会打印警告,推荐使用UNSAFE_componentWillMount
  3. 但是react官网表示UNSAFE_componentWillMount即将过时,不建议使用
  4. 这个生命周期函数也只会执行一次

这个生命周期函数一般使用较少

示例代码:

class MyCom extends React.Component{
    // 1\. 初始化构造函数
    constructor(props){
        super(props)
        console.log("组件初始化数据");
        // 初始化组件状态
        this.state = {
            count: 0
        }
        // 处理事件函数绑定组件实例
        this.handleClick = this.handleClick.bind(this)    
    }

    // 2.组件渲染前执行
    UNSAFE_componentWillMount(){
        console.log("组件内容渲染前执行 conponentWillMount");

    }

    handleClick(){
        this.setState(() => ({
            count: ++this.state.count
        }))

    }
    render(){
        return (
            <div>
                <p>点击次数{ this.state.count }</p>
                <button onClick={ this.handleClick }>点击</button>
            </div>
        )
    }
}

// 将组件渲染到页面上
ReactDOM.render(<MyCom/> ,document.getElementById("root"))

2.1.4 render渲染函数

说明:

  1. class组件中唯一必须实现的方法,其他生命周期函数没有需求可以不写,这个必须实现
  2. render函数返回一个通过JSX语法创建的React元素
  3. render函数应为纯函数,意味着在不修改组件状态和父组件传递的props时,每次返回相同的结果
  4. render函数初始只会渲染一次,但是每次状态的改变都会重新执行

示例代码:

class MyCom extends React.Component{
    // 1\. 初始化构造函数
    constructor(props){
        super(props)
        console.log("组件初始化数据");
        // 初始化组件状态
        this.state = {
            count: 0
        }
        // 处理事件函数绑定组件实例
        this.handleClick = this.handleClick.bind(this)    
    }

    // 2.组件渲染前执行
    UNSAFE_componentWillMount(){
        console.log("组件内容渲染前执行 conponentWillMount");

    }

    // 3\. render渲染函数
    render(){
        console.log("render 渲染函数")
        return (
            <div>
                <p>点击次数{ this.state.count }</p>
                <button onClick={ this.handleClick }>点击</button>
            </div>
        )
    }

    // 自定义事件函数
    handleClick(){
        this.setState(() => ({
            count: ++this.state.count
        }))

    }
}

// 将组件渲染到页面上
ReactDOM.render(<MyCom/> ,document.getElementById("root"))

2.1.5 componentDidMount函数

说明:

  1. 组件渲染完毕以后执行, 在render渲染函数之后
  2. componentDidMount生命周期函数只会执行一次
  3. 可以在这个函数中发送ajax请求

示例代码:

class MyCom extends React.Component{
    // 1\. 初始化构造函数
    constructor(props){
        super(props)
        console.log("组件初始化数据");
        // 初始化组件状态
        this.state = {
            count: 0
        }
        // 处理事件函数绑定组件实例
        this.handleClick = this.handleClick.bind(this)    
    }

    // 2.组件渲染前执行
    UNSAFE_componentWillMount(){
        console.log("组件内容渲染前执行 conponentWillMount");

    }

    // 3\. render渲染函数
    render(){
        console.log("render 渲染函数")
        return (
            <div>
                <p>点击次数{ this.state.count }</p>
                <button onClick={ this.handleClick }>点击</button>
            </div>
        )
    }

    // 4.组件渲染完毕后执行 
    componentDidMount(){
        console.log("组件内容渲染完毕,componentDidMount");

    }

    // 自定义事件函数
    handleClick(){
        this.setState(() => ({
            count: ++this.state.count
        }))

    }
}

// 将组件渲染到页面上
ReactDOM.render(<MyCom/> ,document.getElementById("root"))

2.2 组件渲染更新

组件的更新会出现两种状况, 父组件传递的props更新以及当前组件更新自己的state

2.2.1 组件渲染更新生命周期函数认识
  1. componentWillReceiveProps 组件接受的Props将要更新
  2. shouldComponentUpdate 是否允许组件渲染更新,函数返回true表示通过, false表示不通过,渲染不更新
  3. componentWillUpdate/UNSAFE_componentWillUpdate 组件内容更新渲染前执行
  4. render 组件内容更新渲染
  5. componentDidUpdate 组件内容更新渲染之后执行
2.2.2 componentWillReceiveProps函数

说明:

  1. 在父组件传递的props更新时执行的生命周期函数
  2. 函数接受一个参数nextProps,为更新后的props数据
  3. 使用时控制台会打印警告, 建议使用UNSAFE_componentWillReceiveProps
  4. 但是官网表示UNSAFE_componentWillReceiveProps也将会被废弃

示例代码如下:

// 子组件
class MyCom extends React.Component{

  // 初始化组件状态
  state = {
    count: 0
  }

  // 1\. 组件将要接受props更新
  componentWillReceiveProps(){
    console.log("组件将要接受props更新: componentWillReceiveProps");
  }

  render(){
    console.log("render 渲染函数")
    return (
      <div>
        <p>父组件传递props数据{ this.props.num }</p>
        <p>子组件state数据{ this.state.count }</p>
        <button onClick={ this.handleClick }>子组件按钮</button>
      </div>
    )
  }

  // 自定义事件函数
  handleClick=()=>{
      this.setState(() => ({
        count: ++this.state.count
      }))

  }
}

// 父组件
class MyParent extends React.Component{
  state = {
    num:0
  }

  changeNum = () => {
    this.setState(() => ({
      num: ++ this.state.num
    }) )
  }

  render(){
    return (
      <div>
        <button onClick={ this.changeNum }>父组件按钮</button> 
        <MyCom num={this.state.num}/>
      </div>
    )
  }
}

// 将组件渲染到页面上
ReactDOM.render(<MyParent /> ,document.getElementById("root"))

2.2.3 shouldComponentUpdate函数

说明:

  1. shouldComponentUpdate函数使用来判读是否更新渲染组件
  2. 函数返回值是一个布尔值,为true,表示继续走其他的生命周期函数,更新渲染组件
  3. 如果返回一个false表示,不在继续向下执行其他的生命周期函数,到此终止,不更新组件渲染
  4. 函数接受两个参数, 第一个参数为props将要更新的数据, 第二个参数为state将要更新的数据

示例代码如下:

// 子组件
class MyCom extends React.Component{

  // 初始化组件状态
  state = {
    count: 0
  }

  // 1\. 组件将要接受props更新
  componentWillReceiveProps(nextProps){
    console.log("组件将要接受props更新: componentWillReceiveProps");

  }

  // 2\. 是否允许组件渲染更新
  shouldComponentUpdate(nextProps, nextState){
    console.log("是否允许组件渲染更新: shouldComponentupdate");
    return true
  }

  render(){
    console.log("render 渲染函数")
    return (
      <div>
        <p>父组件传递props数据{ this.props.num }</p>
        <p>子组件state数据{ this.state.count }</p>
        <button onClick={ this.handleClick }>子组件按钮</button>
      </div>
    )
  }
  // 自定义事件函数
  handleClick=()=>{
      this.setState(() => ({
        count: ++this.state.count
      }))

  }
}

// 父组件
//...

2.2.4 componentWillUpdate 函数

说明:

  1. componentWillUpdate组件更新渲染前执行
  2. 函数接受两个参数,第一个是props将要更新的数据,第二个是state将要更新的数据
  3. 使用是浏览器会警告, 建议使用UNSAFE_componentWillUpdate
  4. 但是官网表示UNSAFE_componentWillUpdate也将被废弃

示例代码:

class MyCom extends React.Component{

  // 初始化组件状态
  state = {
    count: 0
  }

  // 1\. 组件将要接受props更新
 componentWillReceiveProps(nextProps){
    console.log("组件将要接受props更新: componentWillReceiveProps");

  }

  // 2\. 是否允许组件渲染更新
  shouldComponentUpdate(nextProps, nextState){
    console.log("是否允许组件渲染更新: shouldComponentupdate");
    return true
  }

  // 3.组件渲染更新前
  componentWillUpdate(nextProps, nextState){
    console.log("组件内容更新前: componentWillUpdate");

  }

  render(){
    console.log("render 渲染函数")
    return (
      <div>
        <p>父组件传递props数据{ this.props.num }</p>
        <p>子组件state数据{ this.state.count }</p>
        <button onClick={ this.handleClick }>子组件按钮</button>
      </div>
    )
  }

  // 自定义事件函数
  handleClick=()=>{
      this.setState(() => ({
        count: ++this.state.count
      }))

  }
}

// 父组件
//... 

2.2.5 render函数

更初始化一样,没事数据更新都会触发render函数重新执行, 更新页面渲染

2.2.6 componentDidUpdate函数

说明:

  1. 组件render执行后,页面渲染完毕了以后执行的函数
  2. 接受两个参数,分别为更新前的props和state

示例代码如下:

// 子组件
class MyCom extends React.Component{

  // 初始化组件状态
  state = {
    count: 0
  }

  // 1\. 组件将要接受props更新
 componentWillReceiveProps(nextProps){
    console.log("组件将要接受props更新: componentWillReceiveProps");

  }

  // 2\. 是否允许组件渲染更新
  shouldComponentUpdate(nextProps, nextState){
    console.log("是否允许组件渲染更新: shouldComponentupdate");
    return true
  }

  // 3.组件渲染更新前
  componentWillUpdate(){
    console.log("组件内容更新前: componentWillUpdate");

  }

  // 4\. render渲染函数
  render(){
    console.log("render 渲染函数")
    return (
      <div>
        <p>父组件传递props数据{ this.props.num }</p>
        <p>子组件state数据{ this.state.count }</p>
        <button onClick={ this.handleClick }>子组件按钮</button>
      </div>
    )
  }

  // 5\. 组件内容更新渲染后
  componentDidUpdate( prevProps, prevState){
    console.log("组件内容更新后执行");
  }

  // 自定义事件函数
  handleClick=()=>{
      this.setState(() => ({
        count: ++this.state.count
      }))

  }
}

// 父组件
//...

2.3 组件销毁

说明:

  1. 组件销毁阶段只有一个生命周期函数componentWillUnmount
  2. componentWillUnmont组件销毁前执行的生命周期函数,
  3. 没有组件销毁后执行的生命周期函数, 没什么意义,组件被销毁了,获取不到对应的内容了
  4. 通过会在组件销毁前清理一些不会被组件自动清理的内容, 如: 定时器,或一些特殊的事件绑定

示例代码:

// 子组件
class MyCom extends React.Component{

    // 初始化组件状态
    state = {
        count: 0
    }

    render(){
        console.log("render 渲染函数")
        return (
            <div>
                <p>父组件传递props数据{ this.props.num }</p>
                <p>子组件state数据{ this.state.count }</p>
                <button onClick={ this.handleClick }>子组件按钮</button>
            </div>
        )
    }

    componentWillUnmount(){
        console.log("组件被销毁前执行:componentWillUnmount")
    }

    // 自定义事件函数
    handleClick=()=>{
        this.setState(() => ({
            count: ++this.state.count
        }))

    }
}

// 父组件
class MyParent extends React.Component{
    state = {
        isShow: true
    }

    changeNum = () => {
        this.setState(() => ({
            isShow: !this.state.isShow
        }) )
    }

    render(){
        return (
            <div>
                <button onClick={ this.changeNum }>父组件按钮</button> 
                { this.state.isShow ? <MyCom num={this.state.num}/>: "组件不显示"}
            </div>
        )
    }
}

// 将组件渲染到页面上
ReactDOM.render(<MyParent /> ,document.getElementById("root"))

2.4 getSnapshotBeforeUpdate函数

说明:

  1. getSnapshotBeforeUpdate必须跟componentDidUpdate一起使用,否则就报错
  2. 但是不能与componentWillReceivePropscomponentWillUpdate一起使用
  3. state和props更新都会触发这个函数的执行, 在render函数之后执行
  4. 接受两个参数,更新前的props和当前的state
  5. 函数必须return 返回结果
  6. getSnapshotBeforeUpdate返回的结果将作为参数传递给componentDidUpdate

示例代码如下:

class MyCom extends React.Component{

  // 初始化组件状态
  state = {
    count: 0
  }

  render(){
    console.log("render 渲染函数")
    return (
      <div>
        <p>父组件传递props数据{ this.props.num }</p>
        <p>子组件state数据{ this.state.count }</p>
        <button onClick={ this.handleClick }>子组件按钮</button>
      </div>
    )
  }

  getSnapshotBeforeUpdate(){
    console.log("getSnapshotBeforeUpdate")

    return true
  }

  componentDidUpdate(){
    console.log("组件内容更新后执行");

  }

  // 自定义事件函数
  handleClick=()=>{
      this.setState(() => ({
        count: ++this.state.count
      }))
  }
}

// 父组件
class MyParent extends React.Component{
  state = {
    isShow: true,
    num : 0
  }

  changeShow = () => {
    this.setState(() => ({
      isShow: !this.state.isShow
    }) )
  }

  changeNum = () => {
    this.setState(() => ({
      num: ++this.state.num
    }) )
  }

  render(){
    return (
      <div>
        <button onClick={ this.changeShow }>父组件按钮</button> 
        <button onClick={ this.changeNum }>更新props</button> 
        { this.state.isShow ? <MyCom num={this.state.num}/>: "组件不显示"}
      </div>
    )
  }
}

// 将组件渲染到页面上
ReactDOM.render(<MyParent /> ,document.getElementById("root"))

2.5 生命周期函数参数
image
2.6 特殊情况的生命周期函数

在React 17 版本之后将会改变几个生命周期函数

image

3. React 新增生命周期函数

3.1 新版生命周期图

添加静态方法后的生命周期函数图

image image
3.2 新增的静态方法

说明:

  1. react新增了静态方法getDerviedStateFromProps方法在生命周期中
  2. 这个方法用来替换componentWillReceiveProps,
  3. 通常会在ComponentWillReceiveProps中利用Props更新state
  4. getDerivedStateFromProps方法接受两个参数, 将要更新的props和state属性
  5. 需要返回一个布尔值,不然会报错
  6. 还可以取代componentWillMount的功能, 因为这个静态方法在组件初始化也会执行

示例代码:

class MyCom extends React.Component{

  // 初始化组件状态
  state = {
    count: 0
  }

  // 生命周期上新增的静态方法
  static getDerivedStateFromProps(nextProps,nextState){
    console.log("getDerivedStateFromProps");

      // 利用props的值更新当前组件的状态
    nextState.count = nextProps.num
    return true
  }

  render(){
    console.log("render 渲染函数")
    return (
      <div>
        <p>父组件传递props数据{ this.props.num }</p>
        <p>子组件state数据{ this.state.count }</p>
        <button onClick={ this.handleClick }>子组件按钮</button>
      </div>
    )
  }

  // 自定义事件函数
  handleClick=()=>{
      this.setState(() => ({
        count: ++this.state.count
      }))

  }
}

// 父组件
class MyParent extends React.Component{
  state = {
    isShow: true,
    num : 0
  }

  changeShow = () => {
    this.setState(() => ({
      isShow: !this.state.isShow
    }) )
  }

  changeNum = () => {
    this.setState(() => ({
      num: ++this.state.num
    }) )
  }

  render(){
    return (
      <div>
        <button onClick={ this.changeShow }>父组件按钮</button> 
        <button onClick={ this.changeNum }>更新props</button> 
        { this.state.isShow ? <MyCom num={this.state.num}/>: "组件不显示"}
      </div>
    )
  }
}

// 将组件渲染到页面上
ReactDOM.render(<MyParent /> ,document.getElementById("root"))

4. 组件更新的方法

组件更新自己的状态,除了使用setState更新外,还可以通过forceUpdate更新

4.1 forceUpdate

说明:

  1. 在组件中也可以组件实例调用forceUpdate方法直接更新数据
  2. forceUpdate方法会强制更新状态,
  3. forceUpdate方法会执行静态方法getDerivedStateFromProps函数
  4. 但是forceUpdate方法不会触发shouldComponetUpdate判断是否更新的生命周期函数

示例代码:

class MyCom extends React.Component{

    // 初始化组件状态
    state = {
        count: 0
    }

    // 2\. 是否允许组件渲染更新
    shouldComponentUpdate(nextProps, nextState){
        console.log("是否允许组件渲染更新: shouldComponentupdate");
        // nextState.count = nextProps.num
        return true
    }

    static getDerivedStateFromProps(nextProps,nextState){
        console.log("getDerivedStateFromProps");

        console.log(arguments);

        return true
    }

    // 自定义事件函数
    handleClick=()=>{
        this.state.count = ++ this.state.count

        this.forceUpdate();
    }

    // 4\. render渲染函数
    render(){
        console.log("render 渲染函数")
        return (
            <div>
                <p>父组件传递props数据{ this.props.num }</p>
                <p>子组件state数据{ this.state.count }</p>
                <button onClick={ this.handleClick }>子组件按钮</button>
            </div>
        )
    }
}

// 父组件
//...

示例说明:

  1. 示例中直接修改状态并不会触发重新渲染
  2. 但是通过组件实例调用forceUpdate强制更新,会重新触发页面渲染
  3. 会触发生命周期getDerivedStateFromProps函数执行,
  4. 但是不会是否判断是否更新的shouldComponentUpdate函数的执行

5. 生命周期总结

5.1 常用生命周期函数

说明:

  1. React生命周期函数很多, 但是并不是每一个都是那么的常用
  2. 因此可以将生命周期图简化一下

常用生命周期图

image
5.2 生命周期总结
5.2.1 组件的三个生命周期分三个阶段
  1. Mount : 初始化插入真实DOM
  2. Update : 数据更改重新渲染
  3. Unmount: 被移出真实的DOM
5.2.2 生命周期不同阶段的钩子函数
  • 第一次初始化渲染显示: ReactDOM.render()

    • constructor(): 创建对象初始化state

    • componentWillMount() : 将要插入回调

    • render(): 用于插入虚拟DOM回调

    • componentDidMount() : 已经插入回调(启动定时器,发送ajax,只执行一次)

  • 每次更新 state: this.setState()

    • componentWillUpdate() : 将要更新回调

    • render() : 更新(重新渲染)

    • componentDidUpdate() : 已经更新回调

  • 移除组件 : ReactDOM.unmountComponentAtNode(containerDom)

    • componentWillUnmount() : 组件将要被移出回调(收尾工作,例如清除定时器)
5.2.3 重要的钩子函数
  • render(): 初始化渲染或更新渲染调用

  • componentDidMount() : 开启监听,发送ajax请求

  • componentWillUnmount(): 做一些收尾工作,如,清理定时器

5.3 示例代码:

// 1\. 定义组件
class Files extends React.Component {

    constructor (){
        super()

        // 定义状态
        this.state = {
            opacity: 1
        }

    }
    removeComponent () {
        // 执行unmountComponentAtNode()移出DOM节点
        ReactDOM.unmountComponentAtNode(document.getElementById('root'))
    }

    // 组件添加完后执行的钩子函数
    componentDidMount () {
        console.log('componentDidMount()')

        // 开启定时器
        this.timer = setInterval(function(){
            console.log('定时器...')

            // 1\. 获取状态中的值
            let {opacity} = this.state;

            // 2\. 改变透明度
            opacity -= 0.1;

            // 3\. 判断透明度,如果小于0,就变为1
            if(opacity <= 0){
                opacity = 1
            }

            // 4\. 改变状态
            this.setState({
                opacity
            })

        }.bind(this),200)
    }

    // 组件被移出后执行的钩子函数
    componentWillUnmount(){
        console.log('componentWillUnmount()')

        // 组件被移除后清除定时器
        clearInterval(this.timer)
    }

    render(){
        console.log('render()')
        // 取出状态中的透明度
        let {opacity} = this.state;

        return (
            <div>
                <h2 style={{opacity:opacity}}>{this.props.msg}</h2>
                <button onClick={this.removeComponent}>删除组件</button>
            </div> 
        )
    }
}

// 设置props类型
Files.propTypes = {
    msg: PropTypes.string
}

// 2\. 渲染组件标签
ReactDOM.render(
    <Files msg="我太难了" />, 
    document.getElementById('root')
)

相关文章

  • React概念图

    React概念图 React组件生命周期概念图 参考文档:React入门教程 组件生命周期React:组件生命周期...

  • React 组件生命周期

    组件生命周期 参考阅读: component-lifecycle react组件生命周期过程说明 react 组件...

  • React总结

    [toc] 1.React组件生命周期 1.1 生命周期图 组件的生命周期的图如下: 具体可参考React 组件生...

  • 学习并实现react (4)

    实现生命周期 生命周期介绍 React 生命周期图 React 子组件在父组件下的生命周期流程 实现 compon...

  • react(最近搞了一套react项目的视频 全套 有需

    React 组件生命周期在本章节中我们将讨论 React 组件的生命周期。 组件的生命周期可分成三个状态: Mou...

  • Notes On React - Two

    React 的生命周期   React组件 的生命周期大致可分成四个状态:  - Mounting:装配-组件实例...

  • 006@React组件的生命周期.md

    006@React组件的生命周期.md React Native 是基于组件化开发。弄清楚组件的生命周期对于我们开...

  • React 生命周期

    React 生命周期 初始化周期 组件重新渲染生命周期 组件卸载生命周期

  • react组件的生命周期

    第三单元(react组件的生命周期) 课程目标 灵活掌握react组件的生命周期以及组件的活动过程。 能够灵活使用...

  • 四:React 进阶三 (生命周期)

    react(一):组件的生命周期 生命周期函数 在组件运行的某个时刻,会被自动执行的一些函数。 React生命周期...

网友评论

    本文标题:第八节:React组件的生命周期

    本文链接:https://www.haomeiwen.com/subject/grtgvrtx.html