react 生命周期 & 执行顺序

- react生命周期

img
  • 第一步:初始化阶段,即( constructor() ),继承了基类,才会有render() 方法,生命周期才能使用。【这也是为什么函数组件不能使用这些方法的原因!!】;super(),用来调用基类的构造方法,将父组件的props注入子组件【props只读,不可变;state可变】

  • 第二步:挂载阶段,componentWillMount()挂载前,调用一次,这里调用this.state不会引起组件重新渲染【这里的内容可以提到constructor中,所以很少使用】;render()根据props和state,render一个UI,不负责实际渲染,之后由React自身根据此元素去渲染出DOM。render是纯函数,不能在里面执行this.setState(),会有改变组件状态的副作用!;componentDidMount():组件挂载到DOM后调用,方法会在组件已经被渲染到 DOM 中后运行,只会调用一次!

  • 第三步:组件更新阶段,【⚠️setState引起的state更新、父组件重新render引起的props更新,更新后的state、props无论是否有变化都会引起子组件重新更新render!!这里可以用shouldComponentUpdate()来优化】;

    • componentWillReceiveProps(nextProps)此方法只调用于props引起的组件更新过程中,参数nextProps是父组件传给当前组件的新props,在此方法中来查明重传的props是否改;将props转化成自己的state【在这里调用this.setState()将不会引起第二次渲染!】因为此方法会判断props是否变化了,若变化了this.setState()将引起state变化,进而引起render变化,此时就没必要在做第二次因重传props引起的render了;

    • shouldComponentUpdate(nextProps, nextState)返回true继续执行,false阻止组件更新,减少不必要的渲染,优化性能;就算上一个方法执行了this.state更新了state,但在render之前此方法中的this.state依然指向更新之前的!!!,否则就永远是true了;

    • componentWillUpdate(nextProps, nextState)在render之前执行,进行更新前的操作,比较少用;

    • render()重新调用

    • componentDidUpdate(prevProps, prevState)此方法在组件更新后被调用,可以操作组件更新的DOM,prevProps和prevState指组件更新前的props和state;

  • 第四步:卸载阶段:componentWillUnmount()在组件被卸载前调用,可以执行一些清理工作,如清除定时器,清除挂载后手动创建的DOM,避免内存泄漏。

img

原来的生命周期在16 Fiber之后就不适合了,因为如果要开启async rendering,在render之前的所有函数都可能被执行多次!!!

  • 16之前,在render前执行的生命周期:comonentWillMount()、componentWillReceiveProps()、shouldComponentUpdate()、componentWillUpdate(),如果在以上的方法中做ajax请求,那ajax会被无谓调用多次;如果在componentWillMount中发起ajax,不管多快也赶不上首次render,而且此方法在服务端渲染也会被调用到,这样的io操作放在componentDidMount里更合适。

  • 所以,除了shouldComponentUpdate()其他render前的函数都被getDerivedStateFromProps替代;即用一个静态函数来取代deprecate的几个生命周期函数,强制在render前只做无副作用的操作,而且能做的操作局限在根据props和state决定更新的state。

  • static getDerivedStateFromProps(props, state)在组件创建时和更新时的render方法之前调用,应该返回一个对象来更新状态,或者返回null来不更新内容。

  • getSnapshotBeforeUpdate(prevProps, prevState)被调用于render之后,可以读取但无法使用DOM的时候;使组件在可能更改之前从DOM捕获一些信息(如滚动位置)。此生命周期返回的任何值,都将作为参数传递给componentDidUpdate()

  • componentDidUpdate(prevProps, prevState, snapshot),snapshot为上一个传过来的值

class ScrollingList extends React.Component {
  constructor(props) {
    super(props);
    this.listRef = React.createRef();
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    //我们是否要添加新的 items 到列表?
    // 捕捉滚动位置,以便我们可以稍后调整滚动.
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    //如果我们有snapshot值, 我们已经添加了 新的items.
    // 调整滚动以至于这些新的items 不会将旧items推出视图。
    // (这边的snapshot是 getSnapshotBeforeUpdate方法的返回值)
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      <div ref={this.listRef}>{/* ...contents... */}</div>
    );
  }
}

- react生命周期执行顺序

  • 只执行一次: constructor、componentWillMount、componentDidMount

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

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

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

假设:APP有parent组件,parent有child组件

  • 不涉及setState更新的话:
App:   constructor --> componentWillMount -->  render --> 
parent: constructor --> componentWillMount -->  render --> 
child:    constructor --> componentWillMount -->  render  --> 
componentDidMount (child) -->  componentDidMount (parent) --> componentDidMount (App)
  • APP的setState事件
App:   componentWillUpdate --> render --> 
    parent: componentWillReceiveProps --> componentWillUpdate --> render --> 
    child:    componentWillReceiveProps --> componentWillUpdate --> render -->
    componentDidUpdate (child) -->  componentDidUpdate (parent) --> componentDidUpdate (App)
  • 触发parent的setState
parent: componentWillUpdate --> render --> 
child:     componentWillReceiveProps --> componentWillUpdate --> render --> 
componentDidUpdate (child) -->  componentDidUpdate (parent) 
  • child组件自身的setState
child: componentWillUpdate --> render -->  componentDidUpdate (child)
  • 结论:完成顺序从根部到子部,完成时从子部到根部(类似事件机制);组件setState不能触发父组件的生命周期更新函数,只能触发更低一级别的生命周期更新函数。

    • 子组件接收的this.propscomponentWillReceivePropsnextProps一样,是最新的,所以componentWillReceiveProps没什么用处;但是在constructor函数中初始化了某个state,必须用 componentWillReceiveProps来更新state,不可省去,否则render中的state将得不到更新。 同时如果您想在子组件监听watch值变化做处理,也可以用到componentWillReceiveProps

    • render中不能使用setState,或componentWillReceiveProps进行向上分发,会造成死循环

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,825评论 6 546
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,814评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,980评论 0 384
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 64,064评论 1 319
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,779评论 6 414
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 56,109评论 1 330
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 44,099评论 3 450
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,287评论 0 291
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,799评论 1 338
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,515评论 3 361
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,750评论 1 375
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,221评论 5 365
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,933评论 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,327评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,667评论 1 296
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,492评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,703评论 2 380

推荐阅读更多精彩内容

  • 作为一个合格的开发者,不要只满足于编写了可以运行的代码。而要了解代码背后的工作原理;不要只满足于自己的程序...
    六个周阅读 8,482评论 1 33
  • 生命周期流程图简单如下: 组件让你把用户界面分成独立的,可重复使用的部分,并且将每个部分分开考虑。React.Co...
    Simple_Learn阅读 1,094评论 0 0
  • 40、React 什么是React?React 是一个用于构建用户界面的框架(采用的是MVC模式):集中处理VIE...
    萌妹撒阅读 1,038评论 0 1
  • React 生命周期很多人都了解,但通常我们所了解的都是单个组件的生命周期,但针对Hooks 组件、多个关联组件(...
    前端js阅读 7,076评论 3 7
  • 今天我犯了一个错误,我摔碎了我的手机屏。我不是故意的,我和我妈去买衣服,试衣服的时候我把外衣脱了放在沙发上,手机...
    幻宇阅读 150评论 0 1