重学React基础知识整理——老的生命周期函数(六)

116 阅读6分钟

React老的生命周期总体简述

1、初始化阶段

constructor();constructor函数在业界把它放入生命周期函数是存疑的,这里我是倾向于放入生命周期函数的,官方也是把它放在挂载阶段的,这个个函数里我们可以继承父组件的props和初始化组件的state。
componentWillMount:render之前最后一次修改状态的机会,在16.2版本之后被废弃要使用需要加上UNSAFE_的前缀。
render:只能访问this.props和this.state,不允许直接修改状态和DOM。
componentDidMount:成功render并渲染完成真实DOM之后触发,可以修改DOM。

2、运行中阶段

componentWillReceiveProps:父组件修改属性会触发该周期函数
shouldComponentUpdate:返回false会阻止render调用,这里一般做class组件的性能优化的工作。
componentWillUpdate:在这个周期函数内不能修改属性和状态。
render:只能访问this.props和this.state,不允许直接修改状态和DOM。
componentDidUpdate:可以修改DOM。

3、销毁阶段

componentWillUnmount:在删除组件之前进行清洗操作,比如销毁计时器和事件监听器

注意:大部分的生命周期函数是在新版本复用的,但是有些生命周期函数是React不推荐使用的。具体包括如下:

a、初始化阶段的 UNSAFE_componentWillMount(),这里的意思是componentWillMount()周期函数加了UNSAFE_的前缀。
b、更新阶段的UNSAFE_componentWillUpdate()、UNSAFE_componentWillReceiveProps()
一共是这三个周期函数被遗弃了,要使用必须加上UNSAFE_,不然react会报警告。

React老的生命周期具体剖析

初始化阶段的constructor()

constructor(props){
    super(props)
    //注意:在派生类中,必须先调用 super() 才能使用 "this"。
    this.state={
      value:'Bob'
    }
  }

在constructor函数里注意要加super().具体原因分析如下:
a、constructor 是一种用于创建和初始化class创建的对象的特殊方法。
b、在一个类中只能有一个名为 “constructor” 的特殊方法。多个会报错。
c、在一个构造方法中可以使用super关键字来调用一个父类的构造方法。
d、如果没有显式指定构造方法,则会添加默认的 constructor 方法。
e、如果不指定一个构造函数 (constructor) 方法,则使用一个默认的构造函数 (constructor)。
f、如果不指定构造方法,则使用默认构造函数。对于基类,默认构造函数是:

constructor() {}

对于派生类,默认构造函数是:

constructor(...args) {
  super(...args);
}

构造函数的形式有上面两种形式。由此可以内推,我们在react中的class组件里,使用构造函数,是一个派生类的构造函数,它的基类是React.Component,所以要写super去调用父类的构造函数,并把props传递给子类。注意:在派生类中,必须先调用 super() 才能使用 "this"。所以才可以给state去初始化赋值,不然this.state会报错。

初始化阶段的componentWillMount()

UNSAFE_componentWillMount() 在挂载之前被调用。它在 render() 之前调用,因此在此方法中同步调用 setState() 不会触发额外渲染,这个是我们在render之前最后一次有机会修改state。通常,我们建议使用 constructor() 来初始化 state。
注意:不要在此周期函数中引入订阅和修改DOM。此周期函数是服务端渲染唯一会调用的生命周期函数。

初始化阶段的render()和更新阶段的render()

a、render()是class组件中唯一必须实现的方法。 b、render()是纯函数,不能在这个周期函数中修改组件的props和state,也不直接做操作dom的操作,如要操作dom要迁移到其他周期函数中。 c、render()的在组件每次调用setState去改变state都会触发render()重新渲染。 d、render()里return返回的是一个最外面没有并列节点的React 元素,代码描述下会更清晰

render() {
    return (
      <div>
        {/* <HelloWorld /> */}
        {/* <HelloWroldState /> */}
        {/* <Range/> */}
        {/* <NewRange/> */}
        {/* <NewRangeDemo/> */}
        {/* <MyInput/> */}
        {/* <Parent/> */}
        {/* <EvenBus/> */}
        {/* <ContextPage/> */}
        <MySlot/>
      </div>
    )
  }

由最外层div包裹。

初始化阶段的 componentDidMount

a、这个个周期函数表示在组件挂载后(组件插入DOM树后),会立即触发。
b、操作DOM节点的操作应该放在这里。
c、这里可以添加订阅,注意要在销毁周期函数中取消订阅。
d、不建议在此初始化state状态,因为在此直接调用setState会触发额外的渲染。

更新阶段的 componentWillReceiveProps

a、会在已挂载的组件接收新的 props 之前被调用,注意:父组件修改属性会触发该周期函数。
b、UNSAFE_componentWillReceiveProps(nextProps) 这里会取到最新的props。在这个周期函数中可以比较 this.props 和 nextProps 并在此方法中使用 this.setState() 执行 state 转换
c、这个方法也是被遗弃的需要加前缀。
d、由于新版React引入了react Fiber架构去实现增量渲染,渲染颗粒度更小,该周期函数的执行优先度较低,在海量数据的时候会把这个周期函数给挤掉。

更新阶段的 shouldComponentUpdate(nextProps, nextState)

a、默认行为是 state 每次发生变化组件都会重新渲染。大部分情况下,你应该遵循默认行为,但是如要减少渲染的话就要返回false。
b、当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。返回值默认为 true。

更新阶段的 componentWillUpdate

当组件收到新的 props 或 state 时,会在渲染之前调用

更新阶段的 componentDidUpdate(prevProps, prevState, snapshot)

a、componentDidUpdate() 会在更新后会被立即调用。首次渲染不会执行此方法。
b、可以在 componentDidUpdate() 中直接调用 setState(),但请注意它必须被包裹在一个条件语句里

销毁阶段的componentWillUnmount()

a、componentWillUnmount() 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。
b、componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。

下面是一个运行部分生命周期的例子:

import React, { Component } from 'react'

export default class Range extends Component {
  constructor(){
    super()
    this.state={
      name:'qq'
    }
  }
  // 第一次将要挂载到dom上,可以最后一次修改state
  componentWillMount(){
    console.log('第一次componentWillMount',this.state.name)
    this.setState({
      name:'7uuu'
    })
  }
  //
  componentDidMount(){
    console.log('第一次componentDidMount',this.state.name)
    // 数据请求放在这
    //订阅函数的订阅
    //setInterval
    //基于创建完的dom进行初始化,。。。。。比如BetterScroll组件new出来
  
  }

  shouldComponentUpdate(nextProps,nextState){
    // return true;//更新组件
    // return false // 阻止更新
    //this.state    老的状态
    //nextState     新的状态
    // if(老的状态 !== 新的状态) {
    //   return true
    // }
    // return false
    if(JSON.stringify(this.state)!==JSON.stringify(nextState)){
       return true
    }
    return false

  }



  render() {
    return (
      <div>
        <div>range</div>
        <button onClick={()=>{
          this.setState({name:'3d33'})
        }}>change</button>
        <div>{this.state.name}</div>
      </div>
    )
  }
}