理解React生命周期

constructor

React借用class类的constructor充当初始化钩子。在我们类扩展任何其他具有已定义构造函数的类的情况下,调用一个特殊的函数super非常重要。
React中,因为所有class组件都要继承自Component类或者PureComponent类,因此和原生class写法一样,要在constructor里首先调用super方法,才能获得this

deprecated—componentWillMount

componentWillMount与构造函数没有太大的区别——它也只在初始安装生命周期中调用一次。

许多人会在这个函数中发送请求来获取数据,并期望在初次渲染就绪之前数据是可用的。

事实并非如此,尽管请求将在初次渲染之前被初始化,但在有时调用render之前它无法完成。

由于这一事实,不建议使用此函数可能会导致操作的副作用。

需要注意的是,在服务端渲染时调用此函数,而在这种情况下,不会在服务器上调用对应的componentDidMount,而是在客户端上调用。

在这个函数中使用setState不会触发render

static getDerivedStateFromProps(nextProps, prevState)

这个新的方法根据父组件传来的props按需更新自己的state,主要是来代替componentWillReceiveProps
该方法定义的时候要加一个static关键字,访问不到this对象,在使用的时候,返回一个对象来增量更新组件的state(和setState非常像)

render

千万不要在render生命周期钩子里调用setState,因为setState会引发render,这样就没完没了。

componentDidMount

在组件挂载之后调用,并且只调用一次。
因为这个函数只保证被调用一次,所以它在这里执行ajax请求简直是完美。

deprecated—componentWillReceiveProps(nextProps)

在每次收到props(父组件重新渲染)的时候,在每个更新生命周期中都会调用此函数,而且会传递所有的props,无论props的值是否发生了改变,简单来说就是组件收到新的props或者父组件重新渲染,都会触发这个方法。

如果某个组件的部分state是依赖于父组件中传递过来的props,这个函数是理想的。

  • 注意:即使props没有发生变化,在componentWillReceiveProps也会被调用,这就需要开发者来判断其值是否已经发生改变。
componentWillReceiveProps(nextProps) {
  if(nextProps.myProp !== this.props.myProps) {
    // do something
  }
}

shouldComponentUpdate(nextProps, nextState, nextContext)

默认情况下,所有基于Components的类在收到props时,statecontext改变时,都会触发render。如果重新渲染组件涉及的计算比较复杂(比如生成图表)或者由于某些性能原因而不推荐,则开发人员就需要来控制一下了。当shouldComponentUpdate返回false的时候,就不会触发render

React还提供了一个PureComponent,它与Component的区别是PureComponent自动实现了一个shouldComponentUpdate

shouldComponentUpdate暴露了两个参数,开发者可以通过比较propsnextPropsstatenextState来判断状态到底有没有发生改变,再返回truefalse。要注意一下引用的坑。

deprecated — componentWillUpdate(nextProps, nextState)

shouldComponentUpdate生命周期钩子返回true,或者调用this.forceUpdate之后,会立即执行该生命周期钩子。
要特别注意,componentWillUpdate生命周期钩子每次更新前都会执行,所以不能在这里调用setState,有可能会没完没了。
同样,因为Fiber机制的引入,这个生命周期钩子有可能会多次调用。

componentDidUpdate(nextProps, nextState, snapshot)

componentWillUnmount

这是组件卸载之前的生命周期钩子。

React的最佳实践是,组件中用到的事件监听器、订阅器、定时器都要在这里销毁。

componentDidMount() {
    document.addEventListener('click', () => {});
}

componentDidCatch

在过去,组件内部的JavaScript错误总是扰乱组件状态以至于在下一次渲染中出现一些奇怪的错误,而且这些错误常常由应用中一些更早的错误引起,然而 React 没有提供一种在组件内部解决这些问题的优雅方案,也不能从错误中恢复。

用户界面某处的 JavaScript 错误不应该使整个 APP 崩溃,为了解决这个问题,React16 引进了一个新的概念 —— Error Boundaries

Error Boundaries 可以捕获在其子组件树里抛出的任何错误,打印这些错误,并且返回一个展示错误的界面而不是崩溃掉的页面。Error Boundaries 可以在渲染过程中、在生命周期方法中、以及其子组件的 constructor 中捕获错误

添加了一个叫做 componentDidCatch(error, info) 的新生命周期方法的组件就叫做 Error Boundaries

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  componentDidCatch(error, info) {
    // Display fallback UI
    this.setState({ hasError: true });
    // You can also log the error to an error reporting service
    logErrorToMyService(error, info);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

你仍然可以像正常组件一样使用它

<ErrorBoundary>
  <App />
</ErrorBoundary>

componentDidCatch()方法就像是为组件定制的 JavaScript 中的 catch {} 代码块,只有通过 class 定义的组件才能成为 Error Boundaries,在实践中,绝大多数时候你都希望只定义一个 Error Boundary 然后在应用的里使用。

生命周期

React的生命周期钩子,实际上只有三个过程:

  • 挂载
  • 更新
  • 卸载

老生命周期

  • 挂载

    • constructor
    • componentWillMount
    • render
    • componentDidMount


      挂载
  • 更新

    • componentWillReceiveProps
    • shouldComponentUpdate
    • componentWillUpdate
    • render
    • componentDidUpdate


      父组件触发`render`

      `setState`触发`render`

      调用`forceUpdate`触发
  • 卸载

    • componentWillUnmount

新生命周期

  • 挂载
    • constructor
    • componentWillMount
    • render
    • componentDidMount
  • 更新
    • static getDerivedStateFromProps
    • shouldComponentUpdate
    • render
    • componentDidUpdate
  • 卸载
    • componentWillUnmount


      new-lifecycle.png

最后借一下大佬的图。

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