【react框架】组件的新生命周期(包括错误捕获),分阶段记忆,减少心智负担

前言

按照我的学习理念,学新不学旧,尽量减少心智负担。所以旧的生命周期我就不记录了。

整体和vue也非常像。


生命周期整体图

先上完整生命周期图:
在这里插入图片描述

(图片来源b站尚硅谷免费课程)

废弃了旧版本的三个钩子函数componentWillReceiveProps()componentWillMount()componentWillUpdate(),可不记。

以下分为几个阶段讲解


挂载阶段

constructor

react组件在挂载阶段,先会执行类定义里的constructor构造器(这也是类的特性),初始化阶段

//构造器
constructor(props) {
  super(props);
  //可以做些事,例如初始化状态
  this.state = { count: 0 };
}

getDerivedStateFromProps

接着进入getDerivedStateFromProps钩子

功能:若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromProps()。官方说尽量少用或不用,容易导致代码冗余。

static getDerivedStateFromProps(props, state) { // 需要加静态修饰符 
  console.log("getDerivedStateFromProps", props, state);
  return null; // 必须返回一个null或者state对象,返回的state对象会覆盖state原值,如果直接返回props,那么state的值在任何时候都取决于props,所以叫state派生于prop
}

个人感觉可以放到render中处理,因为更新阶段也会执行render,这样这个钩子就可以不用记了哈哈。

render

然后进入render钩子,渲染阶段

// 写jsx渲染html
render() {
  const { count } = this.state;
  return (
    <div>
		{count}
    </div>
  );
}

componentDidMount

接着进入componentDidMount钩子,组件已挂载阶段

componentDidMount() {
	// 常用,一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息。
}

更新阶段

当props或者state更新后,就会进入组件的更新阶段

getDerivedStateFromProps

这个先

shouldComponentUpdate

先进入shouldComponentUpdate()钩子,控制组件更新的“阀门”:

shouldComponentUpdate() {
  // 不写这个钩子的话,底层默认返回true,自己改写的话必须返回布尔值
  return true; // 如果为false生命周期就不会走下去,被截胡在这
}

这个钩子我有专门讲过,文章

render

然后进入render()钩子

getSnapshotBeforeUpdate

在即将更新视图的时候,像快门一样咔擦停住:

getSnapshotBeforeUpdate() {
  return xxx // 这里可以返回值,在componentDidUpdate可以获取到,例如componentDidUpdate()可以拿到更新前的数据
}

componentDidUpdate(preProps, preState, snapshotValue) {
	// 拿到更新前的props,state,getSnapshotBeforeUpdate的快照值
	console.log(
	  "Count---componentDidUpdate",
	  preProps,
	  preState,
	  snapshotValue
	);
}

可以用于获取前后更新的dom的某些状态,例如高度、滚动高度等等,看需求来要。

componentDidUpdate

再进入componentDidUpdate()钩子,组件更新完成

componentDidUpdate() {}

强制更新

通过调用this.forceUpdate(),不更改任何数据,强制更新,进入生命周期流程,结合上文加看图。


卸载阶段

componentWillUnmount

当组件将要卸载,会进入componentWillUnmount钩子函数,一般会用于清除一些定时器,实例,取消订阅消息等。例如:

componentWillUnmount() {
  //清除定时器
  clearInterval(this.timer); // 防止定时器叠加
}

可以通过ReactDOM.unmountComponentAtNode(document.getElementById(""))来强制卸载组件。


错误捕获

getDerivedStateFromError与componentDidCatch

当有一个子组件出现js报错问题,父组件会在页面上直接渲染不出来,这在生产环境上会给用户带来不好的体验。

react提供了错误处理相关的钩子getDerivedStateFromErrorcomponentDidCatch,能够让项目在生产环境中,不会因为一个子组件的报错而影响父级组件的显示(开发环境还是会报错,但是可以×掉报错页面),该报错组件显示一个我们设定好的界面,可称为错误边界。

// 在父组件中
state = {hasError: false}
static getDerivedStateFromError(error) { // 捕获生命周期和render调用时,发生的错误
    console.log(error); // 在render之前触发
    // 返回新的state
    return {
        hasError: true,
    };
}

componentDidCatch(error, info) {
    // 统计页面的错误。发送请求发送到后台去,为了日后修改bug
    console.log(error, info); // error —— 抛出的错误,info —— 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息
}

// 然后在渲染的时候,如果子组件出错,就用个标签替换一下
render() {
      return (
          <div>
		     {this.state.hasError ? <h1>网络出错了</h2> : <Child />}
	      </div>
      )
 }

简单封装

一般都会封装成一个公共组件src/components/ErrorBoundary/index.js

import React, { Component } from 'react';

export default class ErrorBoundary extends Component {

  constructor(props) {
    super(props);
    this.state = {
      flag: false
    };
  }

  static getDerivedStateFromError(error) {
    console.log(error)
    return {
      flag: true
    }
  }

  /* error: 抛出的错误
   * info: 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息
  */
  componentDidCatch(error, info) {
    
  }

  render() {
    return (
      <div>
        {this.state.flag ? <h1>发生错误,请稍后再试!</h1> : this.props.children}
      </div>
    )
  }
}

然后一般在layout组件中使用(因为可以覆盖到页面内部的所有子组件):

import ErrorBoundary from '@/components/ErrorBoundary';

// 在模板中包裹起来即可
<ErrorBoundary>
	<Zujian>
</ErrorBoundary>

不过我后面试了一下,如果放在layout组件中,当报错了出现错误边界后再切换到其他页面错误边界仍然显示,所以建议还是放在页面组件里吧。

componentDidCatch的注意点

没实践过,大概稍微记录下,可能有错误

  • 开发环境下,错误会冒泡会到window.onerrorwindow.addEventListener('error', callback)
  • 生产环境下,错误不会冒泡,只被componentDidCatch拦截
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值