react之组件生命周期

四个阶段

  • 初始化
  • 运行中
  • 销毁
  • 错误处理(16.3以后)
  1. 初始化
    1. constructor
    2. static getDerivedStateFromProps()
    3. componentWillMount() / UNSAFE_componentWillMount()
    4. render()
    5. componentDidMount()
  2. 更新
    propsstate的改变可能会引起组件的更新,组件重新渲染的过程中会调用以下方法:
    1. componentWillReceiveProps() / UNSAFE_componentWillReceiveProps()
    2. static getDerivedStateFromProps()
    3. shouldComponentUpdate()
    4. componentWillUpdate() / UNSAFE_componentWillUpdate()
    5. render()
    6. getSnapshotBeforeUpdate()
    7. componentDidUpdate()
  3. 销毁
    1. componentWillUnmount()
  4. 错误处理
    1. componentDidCatch()

各个生命周期详解

(1)constructor

  • React组件的构造函数在挂在之前被调用。
  • 调用super(props),用来将父组件传来的props绑定到这个类中,使用this.props将会得到。
  • constructor中应当做些初始化的动作,如:初始化state,将事件处理函数绑定到类实例上,但也不要使用setState()
    使用场景:
    • 初始化state数据
    • 定义函数修改this指向
      constructor(props) {
          super(props);
          this.state = {
              isLiked: props.isLiked
          };
          this.handleFun=this.handleFun.bind(this)
      }
      

(2)static getDerivedStateFromProps(nextProps, prevState)
React 16.3 的版本中 getDerivedStateFromProps 的触发范围是和 16.4^ 是不同的,主要区别是在 setStateforceUpdate 时会不会触发,具体可以看这个生命全周期图
使用场景:

  • 无条件的根据 prop 来更新内部 state,也就是只要有传入 prop 值, 就更新 state
  • 只有 prop 值和 state 值不同时才更新 state 值。
Class ColorPicker extends React.Component {
    state = {
        color: '#000000'
    }
    static getDerivedStateFromProps (props, state) {
        if (props.color !== state.color) {
            return {
                color: props.color
            }
        }
        return null
    }
    ... // 选择颜色方法
    render () {
        .... // 显示颜色和选择颜色操作
    }
}

纯在问题:
现在我们可以这个颜色选择器来选择颜色,同时我们能传入一个颜色值并显示。如果我们传入一个颜色值后,再使用组件内部的选择颜色方法,我们会发现颜色不会变化,一直是传入的颜色值。

这是使用这个生命周期的一个常见 bug。为什么会发生这个 bug 呢?在开头有说到,在 React 16.4^ 的版本中 setStateforceUpdate 也会触发这个生命周期,所以内部 state 变化后,又会走 getDerivedStateFromProps 方法,并把 state 值更新为传入的 prop。

Class ColorPicker extends React.Component {
    state = {
        color: '#000000',
        prevPropColor: ''
    }
    static getDerivedStateFromProps (props, state) {
        if (props.color !== state.prevPropColor) {
            return {
                color: props.color
                prevPropColor: props.color
            }
        }
        return null
    }
    ... // 选择颜色方法
    render () {
        .... // 显示颜色和选择颜色操作
    }
}

注意点:

  • 因为这个生命周期是静态方法,同时要保持它是纯函数,不要产生副作用。
  • 在使用此生命周期时,要注意把传入的 prop 值和之前传入的 prop 进行比较(这个 prop 值最好有唯一性,或者使用一个唯一性的 prop 值来专门比较)。
  • 不使用 getDerivedStateFromProps,可以改成组件保持完全不可控模式,通过初始值和 key 值来实现 prop 改变 state 的情景。

(3) componentWillMount() / UNSAFE_componentWillMount()

  • componentWillMount()将在React未来版本(官方说法 17.0)中被弃用UNSAFE_componentWillMount()在组件挂载前被调用,在这个方法中调用setState()不会起作用,是由于他在render()前被调用。

(4)render()
当他被调用时,他将计算this.propsthis.state,并返回以下一种类型:

  • React元素。通过jsx创建,既可以是dom元素,也可以是用户自定义的组件。
  • 字符串或数字。他们将会以文本节点形式渲染到dom中。
  • Portals。react 16版本中提出的新的解决方案,可以使组件脱离父组件层级直接挂载在DOM树的任何位置。
  • null,什么也不渲染
  • 布尔值。也是什么都不渲染。

注意:返回null,false,ReactDOM.findDOMNode(this)将会返回null,什么都不会渲染
render()方法必须是一个纯函数,他不应该改变state,也不能直接和浏览器进行交互,应该将事件放在其他生命周期函数中。
如果shouldComponentUpdate()返回falserender()不会被调用。

(5)componentDidMount
组件被装配后立即调用。
应用场景:

  • 通常在这里进行ajax请求
  • 初始化第三方的dom库

(6)componentWillReceiveProps()/UNSAFE_componentWillReceiveProps(nextProps)
建议使用getDerivedStateFromProps函数代替

  • 当组件挂载后,接收到新的props后会被调用
  • 如果需要更新state来响应props的更改,则可以进行this.propsnextProps的比较,并在此方法中使用this.setState()
  • 如果父组件会让这个组件重新渲染,即使props没有改变,也会调用这个方法。
  • React不会在组件初始化props时调用这个方法。调用this.setState也不会触发。

(7) shouldComponentUpdate(nextProps, nextState)

  • 渲染新的propsstate前,shouldComponentUpdate会被调用默认为true
  • 这个方法不会在初始化时被调用,也不会在forceUpdate()时被调用。返回false不会阻止子组件在state更改时重新渲染。
  • 如果shouldComponentUpdate()返回falsecomponentWillUpdate,rendercomponentDidUpdate不会被调用。

    官方并不建议在shouldComponentUpdate()中进行深度查询或使用JSON.stringify(),他效率非常低,并且损伤性能

//下次的props和state数据
shouldComponentUpdate(nextProps,nextState){
    if(nextProps.data==this.props.data){
        return false
    }
    return true
}

(8) UNSAFE_componentWillUpdate(nextProps, nextState)
渲染新的stateprops时,UNSAFE_componentWillUpdate会被调用.
将此作为在更新发生之前进行准备的机会。这个方法不会在初始化时被调用
不能在这里使用this.setState(),也不能做会触发视图更新的操作。如果需要更新stateprops,调用getDerivedStateFromProps

(9) getSnapshotBeforeUpdate()
render()后的输出被渲染到DOM之前被调用。

  • 它使您的组件能够在它们被潜在更改之前捕获当前值(如滚动位置)。
  • 这个生命周期返回的任何值都将作为参数传递给componentDidUpdate()。

(10) componentDidUpdate(prevProps, prevState, snapshot)
在更新发生后立即调用componentDidUpdate()
此方法不用于初始渲染。当组件更新时,将此作为一个机会来操作DOM。只要您将当前的props与以前的props进行比较(例如,如果props没有改变,则可能不需要网络请求),这也是做网络请求的好地方。

如果组件实现getSnapshotBeforeUpdate()生命周期,则它返回的值将作为第三个“快照”参数传递给componentDidUpdate()。否则,这个参数是undefined

(11) componentWillUnmount()

在组件被卸载并销毁之前立即被调用。
在此方法中执行任何必要的清理,例如使定时器无效,取消网络请求或清理在componentDidMount中创建的任何监听。

(12) componentDidCatch(error, info)

错误边界是React组件,可以在其子组件树中的任何位置捕获JavaScript错误,记录这些错误并显示回退UI,而不是崩溃的组件树。错误边界在渲染期间,生命周期方法以及整个树下的构造函数中捕获错误。

如果类组件定义了此生命周期方法,则它将成错误边界。在它中调用setState()可以让你在下面的树中捕获未处理的JavaScript错误,并显示一个后备UI。只能使用错误边界从意外异常中恢复; 不要试图将它们用于控制流程。

错误边界只会捕获树中下面组件中的错误。错误边界本身不能捕获错误

PureComponent

PureComponent里如果接收到的新属性或者是更改后的状态和原属性、原状态相同的话,就不会去重新render了
在里面也可以使用shouldComponentUpdate,,而且。
是否重新渲染以shouldComponentUpdate的返回值为最终的决定因素。

import React, { PureComponent } from 'react'
class YourComponent extends PureComponent {
  ……
}

ref

对组件真正实例的引用,其实就是ReactDOM.render()返回的组件实例,ref可以挂载到组件上也可以是dom元素上。

  • 挂到组件(class声明的组件)上的ref表示对组件实例的引用。不能在函数式组件上使用 ref 属性,因为它们没有实例:
  • 挂载到dom元素上时表示具体的dom元素节点。
import React, { Component, createRef } from 'react'
import ReactDOM from 'react-dom'

class App extends Component {
  constructor() {
    super()
    // 创建inputRef
    this.inputRef = createRef()
  }
  componentDidMount () {
    console.log(this.inputRef.current) // <input type="text">
  }
  render () {
    return (
  		<div>
        {/* 关联ref和dom */}
        <input type="text" ref={this.inputRef} />
      </div>
  	)
  }
}
ReactDOM.render(
	<App/>,
  document.getElementById('root')
posted @ 2021-10-13 10:33  久宇诗  阅读(232)  评论(0编辑  收藏  举报