React的生命周期


目录

在组件的整个生命周期中,随着该组件的props或者state发生改变,其DOM表现也会有相应的变化。一个组件就是一个状态机,对于特定地输入,它总返回一致的输出。简单的说:生命周期函数指在某一个时刻组件会自动调用执行的函数。

React生命周期的三个大阶段

  • 1.Mounting: 挂载阶段。(已插入真实 DOM)
  • 2.Updation: 更新阶段。(正在被重新渲染)
  • 3.Unmounting: 销毁阶段(已移出真实 DOM)

React的生命周期图:

React的生命周期图

挂载阶段(加载阶段:涉及5个钩子函数)

这些方法会在组件实例创建和插入DOM中时被调用

1.constructor()

constructor()中完成了React数据的初始化,它接受两个参数:props和context,当想在函数内部使用这两个参数时,需使用super()传入这两个参数。

  • 执行时间:组件被加载前最先调用,并且仅调用一次
  • 作用:定义状态机变量

语法:

constructor(props) {
    super(props);
    this.state = {
      content:null,
    }
  }

注意:构造函数会在挂载前调用。只要使用了constructor()就必须写super(),否则会导致this指向错误。

2.static getDerivedStateFromProps()

这是react16.3之后新增的一个生命周期,这是一个静态方法,静态方法没有this所以不能使用setState,需要return一个对象,这个对象就相当于setState里面的参数。
常用于强制性的根据props来设置state,组件实例化后和接受新属性时调用,返回一个对象以更新状态,或返回null表明不需要更新状态

语法:

static getDerivedstateFromProps(nextProps,prevState){

}

注意:设置了这个生命周期就不能设置componentWillMount()

3.coponentWillMount()

componentWillMount()一般用的比较少,它更多的是在服务端渲染时使用。它代表的过程是组件已经经历了constructor()初始化数据后,挂载阶段前立刻调用,发生在render()之前

  • 执行时间:组件初始渲染(render()被调用前)前调用,并且仅调用一次
  • 作用:如果在这个函数中调用setState改变某些状态机,react会等待setState完成后再渲染组件

语法:

componentWillMount(){
    console.log('componentWillMount----组件将要挂载到页面的时刻')
}

注意:react*17版本之后将废弃。如果还想继续使用,可以使用UNSAFE_componentWillMount来代替。这个生命周期,是除了初始化之外,唯一一个能够直接同步修改state的地方。组件初始化时只调用,以后组件更新不调用,整个生命周期只调用一次,coponentWillMount() 在组件即将被挂载到页面的时刻执行。另外,子组件也有componentWillMount函数,在父组件的该函数调用后再被调用

4.render()

react是整个生命周期中必须的钩子函数,render函数会插入jsx生成的dom结构,react会生成一份虚拟dom树,在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染。此时就不能更改state了。

  • 执行时间:componentWillMount之后,componentDidMount之前,
  • 作用:渲染挂载组件
  • 触发条件:(1)初始化加载页面(2)状态机改变setState ( 3 ) 接收到新的props(父组件更新)

语法:

render(){
    return(
    <div>
    ...
    </div>
    )
}

简单点说:主要用于创建虚拟dom,进行diff算法,更新dom树都在此进行。 页面state或props发生变化时触发render()函数。

5.componentDidMount()

componentDidMount()在组件挂载之前调用一次。如果在这个函数里面调用setState,本次的render函数可以看到更新后的state,并且只渲染一次。

  • 执行时间:render之后被调用,并且仅调用一次
  • 作用:渲染挂载组件;可以使用refs(备注:React支持一个特殊的属性,你可以将这个属性加在任何通过render()返回的组件中。这也就是说对render()返回的组件进行一个标记,可以方便的定位的这个组件实例。)

语法:

componentDidMount(){
    console.log('componentDidMount----组件挂载完成的时刻执行')
}

注意:componentDidMount : 在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。

挂载阶段注意的问题

componentWillMount和componentDidMount这两个生命周期函数,只在页面刷新时执行一次,而render函数是只要有state和props变化就会执行,因为在每一次组件更新时,render()函数都会进行diff算法,来比较更新前后的新旧DOM树。

更新阶段 加载阶段:涉及5个钩子函数)

组件分为两种情况,state改变和props改变。
如果state改变,会直接进行到组件更新的第二个shouldComponentUpdate,如果是props改变,会先走componentWillReceiveProps。

1.componentWillReceiveProps()

componentWillReceiveProps() 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。

语法:

componentWillReceiveProps (nextProps) {
}

注意:

  • 1.在接受父组件改变后的props需要重新渲染组件时用到的比较多
  • 2.接受一个参数nextProps
  • 3.通过对比nextProps和this.props,将nextProps的state为当前组件的state,从而重新渲染组件
  • 4.在挂载了的组件接收到新属性前调用。推荐使用getDerivedStateFromProps生命周期而不是该函数。

2.shouldComponentUpdate()

shouldComponentUpdate() 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。
可以在你确认不需要更新组件时使用。

  • 执行时间:组件挂载后(即执行完render),接收到新的state或props时被调用,即每次执行setstate都会执行该函数,来判断是否重新render组件,默认返回true;接收两个参数:第一个是心的props,第二个是新的state。
  • 作用:如果有些变化不需要重新render组件,可以在该函数中阻拦

语法:

componentWillReceiveProps (nextProps) {
}

注意:
react性能优化非常重要的一环。组件接受新的state或者props时调用,我们可以设置在此对比前后两个props和state是否相同,如果相同则返回false阻止更新,因为相同的属性状态一定会生成相同的dom树,这样就不需要创造新的dom树和旧的dom树进行diff算法对比,节省大量性能,尤其是在dom结构复杂的时候

3.componentWillUpdate()

shouldComponentUpdate返回true以后,组件进入重新渲染的流程,进入componentWillUpdate,这里同样可以拿到nextProps和nextState。

语法:

 componentWillUpdate(nextProps,nextState){}

注意:
componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。

4.render()

和mount阶段一样,生成虚拟DOM

5.componentDidUpdate()

componentDidUpdate()组件更新完毕后,react只会在第一次初始化成功会进入componentDidmount,之后每次重新渲染后都会进入这个生命周期,这里可以拿到prevProps和prevState,即更新前的props和state。

  • 执行时间:重新渲染后调用,在初始化渲染的时候该方法不会被调用
  • 作用:使用该方法可以在组件更新之后操作DOM 元素

语法:

componentDidUpdate(prevProps,prevState){}

注意:
componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用。

卸载阶段 销毁阶段:涉及1个钩子函数)

1.componentWillUnmount()

在父组件中定义一个flag为true的状态值,添加一个按钮声明一个onClick事件去
更改这个flag实现销毁组件。

  • 执行时间:组件被卸载前调用,
  • 作用:在该方法中执行任何必要的清理,比如无效的定时器,或者清除在 componentDidMount 中创建的 DOM 元素。

语法:

componentDidUpdate(prevProps,prevState){}

注意:
componentWillUnmount()组件将要卸载时调用,一些事件监听和定时器需要在此时清除。

补充

1.组件生命周期的执行次数是什么样子的

只执行一次: constructor、componentWillMount、componentDidMount

执行多次:render 、子组件的componentWillReceiveProps、componentWillUpdate、componentDidUpdate

有条件的执行:componentWillUnmount(页面离开,组件销毁时)

不执行的:根组件(ReactDOM.render在DOM上的组件)的componentWillReceiveProps(因为压根没有父组件给传递props)

2.组件生命周期巧记

  • 数据接收 实现继承super(props) :constructor

  • 渲染组件 和 html 标签:render

  • 组件将要挂载时触发的函数:componentWillMount

  • 组件挂载完成时触发的函数:componentDidMount

  • 是否要更新数据时触发的函数(检测组件内的变化 可以用作页面性能的优化(默认值为true)):shouldComponentUpdate

  • 将要更新数据时触发的函数:componentWillUpdate

  • 数据更新完成时触发的函数:componentDidUpdate

  • 组件将要销毁时触发的函数:componentWillUnmount

  • 父组件中改变了props传值时触发的函数( 接收组件传入输入数据):componentWillReceiveProps

3.特别注意

当一个页面中存在子父组件时,要注意componentWillMount和componentDidMount的使用,如果需要先加载父组件(获取网路数据),父组件传值给子组件,再加载子组件(获取网路数据),那么不能同时在子父组件中使用componentDidMount获取网路数据,因为会先执行子组件的componentDidMount,会由于未得到父组件的传值而报错;解决方案:(1)父组件:componentWillMount,子组件:componentDidMount;(2)父组件:componentWillMount,子组件:componentWillMount;
当一个页面中如要实现左右联动效果,(比如:a页面中包含b1(左)和b2(右)页面,单击b1中的知识点,b2页面内容对应变化,b1向b2通过redux传参,b2首次通过 componentDidMount接收,后来通过componentWillReceiveProps接收)

注:文章借鉴

浅析React生命周期函数的使用


文章作者: BiLiang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 BiLiang !
评论
  目录