欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

React(v16.8.4)生命周期详解

程序员文章站 2022-03-11 07:57:15
当前版本v16.8.4 装载过程(组件第一次在DOM树中渲染的过程): constructor(常用) getInitialState(v16.0已废弃) getDefaultProps(v16.0已废弃) componentWillMount(v17.0中将被弃用) getDerivedState ......

当前版本v16.8.4

装载过程(组件第一次在dom树中渲染的过程):

constructor(常用) -> getinitialstate(v16.0已废弃) -> getdefaultprops(v16.0已废弃) -> componentwillmount(v17.0中将被弃用) -> getderivedstatefromprops(v16.3新增,并在v16.4中升级优化了一下) -> render(必须要) -> componentdidmount(常用)

更新过程(当组件被重新渲染的过程,state改变或props改变或父组件forceupdate引发子组件的重新渲染):

componentwillreceiveprops(v17.0中将被弃用) -> getderivedstatefromprops -> shouldcomponentupdate -> componentwillupdate(v17.0中将被弃用) -> render -> getsnapshotbeforeupdate -> componentdidupdate

卸载过程(组件从dom中删除的过程):

componentwillunmount

错误处理(当组件发生错误的时候,用得极少)

getderivedstatefromerror(v16.6新增) -> componentdidcatch(未来将被废弃)

constructor:

es6中每个类的构造函数,并不是每个组件都需要定义自己的构造函数。比如无状态组件。
作用:

  1. 初始化state, 例如super(props)下的 this.state = {}
  2. 绑定成员函数的this环境。例如 this.onclickbutton = this.onclickbutton.bind(this)。但这种方案一般都会用箭头函数代替
    而综合以上两点作用,其实很多时候,你会在antd官网的例子上看到一些例子,并没有使用contructor, 而是直接简写为
  state = {
   count: 0
  }
  // 这是因为在es6的继承中,其实不管子类写不写constructor,在new实例的过程都会给补上constructor
  class colorpoint extends point {
  
  }
  // 等同于 
  class colorpoint extends point {
    constructor(...args) {
      super(...args);
    }
  }

getinitialstate (随着v16.0版本createclass被弃用,该方法也不存在了):

返回值会用来初始化组件的this.state

getdefaultprops (随着v16.0版本createclass被弃用,该方法也不存在了):

返回值可以作为props的初始值

componentwillmount(即将在v17.0中被弃用):

在没被弃用的时候也几乎不用,这时候没有任何渲染出来的结果,即使调用this.setstate修改状态也不会引发重新绘制。所有在这里可以做的事,都可以提前到 constructor中去做。有些人可能用过vue, 在vue中也经常在created中去请求接口,比如可能初始值是0,然后在created中请求接口,简单的理解成想页面在展示的时候就直接显示接口请求返回后的数据1了,而不是我们看到页面的时候先看到0,然后突然变成1了。个人理解vue的created和react的componentwillmount应该也是相差不了太多的,如果是在componentwillmount的时候你的数据还不是1的话,你这时候请求数据,其实是另外开了一个线程去执行异步操作了,render函数并不会等你异步请求结果返回1才去执行render。网络差的话,你先看到0再看到突然变成1也是很正常的事。在这里请求和在componentdidmount中请求并不会有太大的差别。同理,其实vue中特意区分该在created中还是mounted中请求接口也是没必要的,还不如统一到mounted/componentdidmount中去请求接口,因为我们有些方法还是要等真实dom存在后才去执行的

getderivedstatefromprops(props, state)

第一次在装载阶段(当前组件实例化)会被触发比较好理解,但是组件更新阶段,究竟组件更新阶段的什么操作会触发这个函数?
假如我在父组件改变了props 会触发这个函数吗?答案是会。
假如我在当前组件 this.setstate 会触发这个函数吗?在v16.3中不会,但是在v16.4以上就会了。截至2019-03-17,在 上看到的翻译还是错的。不信可以自己试试?
假如我在父组件只是执行了 forceupdate 强行引发一次重新绘制,那当前组件(子组件)的getderivedstatefromprops又会被触发吗?
一样,在v16.3中不会,但是在v16.4以上就会了。
它返回一个对象来更新状态,如果返回的是null就表示不更新任何内容
这个方法react官方都意识到很多人对如何使用它存在许多误解(),
目前很多人的博客其实写得也有点问题的。

render:

返回一个jsx表示的对象,然后由react库来根据返回对象决定如何渲染。并不是返回的真实dom,其他的生命周期都可以省,但是这个必须要

componentdidmount:

仅在浏览器端执行,此时已经有了真实的dom节点,在这个阶段常用于处理接口请求,或者一些事件处理函数

componentwillreceiveprops(nextprops):

当前组件setstate()不会调用;
父组件props改变会调用;
父组件通过forceupdate重新执行render,也会调用当前组件的componentwillreceiveprops;
只要父组件的render函数被调用,那么当前组件(子组件)都会触发这个函数,不管父组件的props发不发生变化。例如父组件执行了 forceupdate 强行引发一次重新绘制。当前组件的componentwillreceiveprops就会被触发。而在当前组件this.setstate是不会触发这个函数的。因为componentwillreceiveprops适合根据新的props值(也就是参数nextprops)来计算出是不是要更新内部状态state。更新组件内部状态的方法就是this.setstate。如果this.setstate的调用导致componentwillreceiveprops再依次被调用,那就是一个死循环了

shouldcomponentupdate(nextprops, nextstate):

当前组件setstate()会调用;
父组件props改变会调用;
父组件通过forceupdate重新执行render,不会调用当前组件的shouldcomponentupdate;
这个方法主要是为了性能优化而设计的,考虑使用内置的purecomponent,而不是自己在这个函数里写比较,更不建议在这个组件里使用json.stringify去深度检查,效率非常低。
这里返回一个布尔值,如果返回false,那这个生命周期后面的都不会执行了

componentwillupdate(nextprops, nextstate):

当前组件setstate()会调用;
父组件props改变会调用;
父组件通过forceupdate重新执行render,也会调用当前组件的shouldcomponentupdate;
不应该在这里使用setstate.这个方法也应该尽量避免使用,将要被遗弃。几乎用不上。应该都统一到componentdidupdate中去处理

getsnapshotbeforeupdate(prevprops, prevstate):

setstate(),props发生改变,父组件重新render都会调用。发生在更新状态的render之后,这时候已经可以读取dom了。通常用于处理滚动位置的聊天线程等ui中。
和getderivedstatefromprops一样它返回一个对象来更新状态,如果返回的是null就表示不更新任何内容

componentdidupdate(prevprops, prevstate):

setstate(),props发生改变,父组件重新render都会调用。这个方法相对用得也比较多。同componentdidmount处理事件函数类似,如果组件被更新的时候,原有的内容被重新绘制后可能也需要再次处理事件函数

componentwillunmount():

当react组件要从dom树上删除掉的时候,这个方法就会被调用。
如果在componentdidmount中使用非react的方法创造了一些dom元素,如果撒手不管可能会造成内存泄漏,那就需要在componentwillunmount中把这些创造的dom元素清理掉

import react, { component } from "react";

export default class lifecycle extends component {
  state = {
  
  }
  static getderivedstatefromprops(props, state) {
  
  }  
  componentdidmount = () => {

  }  
  shouldcomponentupdate = (nextprops, nextstate) => {

  }
  getsnapshotbeforeupdate = (prevprops, prevstate) => {

  }
  componentdidupdate = (prevprops, prevstate) => {
    
  }
  componentwillunmount = () => {
    
  }
  render() {
    return (
      <div>
        
      </div>
    )
  }
}