React 错误边界组件
这是React16的内容,并不是最新的技术,但是用很少被讨论,直到通过文档发现其实也是很有用的一部分内容,还是总结一下~
React中的未捕获的 JS 错误会导致整个应用的崩溃,和整个组件树的卸载。从 React16 开始就是这样。但是同时React也引入了一个新的概念——错误边界。
定义,是什么
错误边界仍然是一种组件,可以捕获(打印或者其他方式)处理该组件的子组件树任何位置的 JavaScript 错误,并根据需要渲染出备用UI.
工作方式类似于try-catch,但是错误边界只用于 React 组件。
只有class组件能够成为错误边界组件。错误边界仅可以捕获子组件的错误,无法捕获自身的错误。
错误边界会在渲染期间,生命周期和整个组件树的构造函数中捕获错误。如果没有错误边界处理,渲染的还是崩溃的子组件树,这显然不是我们想要的。
通过一个例子来逐步演示要怎么用错误边界:
export default class ErrorTest extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<BugCounter></BugCounter>
<span>my name is dan</span>
</div>
);
}
}
// Bug 报错组件
class BugCounter extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0,
};
}
click = () => {
this.setState(({ counter }) => ({ counter: counter + 1 }));
};
render() {
if (this.state.counter === 5) {
throw new Error("crashed!");
}
return (
<div>
<h3 onClick={this.click}>{this.state.counter}</h3>
</div>
);
}
}
上面代码的渲染结果(忽略样式):
点击数字0
,会逐步递增。但是数字等于5
的时候,组件会抛出一个Error
:
该Error
会引起整个Demo
的崩溃,连外部的<span>my name is dan</span>
也显示不出来了,这时还没有添加错误边界。
生产模式下,会直接白屏,并在控制台报错:
getDerivedStateFromError & componentDidCatch
需要一个错误边界来处理这种崩溃。如何定义一个错误边界?
定义一个组件,并实现static getDerivedStateFromError()
或者componentDidCatch()
生命周期方法(可以都实现或者选择其一)。这个组件就会变成一个错误边界。
关于这两个生命周期函数,可以通过链接查看,总结如下:
componentDidCatch(error, info)
error
是抛出的错误对象,而info
则包含了组件引发错误的栈信息。函数在提交阶段被调用。是可以执行副作用的。static getDerivedStateFromError(error)
在子组件抛出错误后调用,会将抛出的错误作为参数。需要返回一个值,以更新state。该函数在渲染阶段调用,不允许出现副作用。如果在捕获错误后需要执行副作用操作,应该在
componentDidCatch
中进行。
制作错误边界组件
可以使用组合的方式,在要使用的组件上面添加一个错误边界组件包裹一层。该组件需要这些效果:
- 捕获子组件错误,组件内部记录出错状态
- 在出错状态下显示备用UI,在正常状态下显示子组件
那么就可以像这样:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染能够显示降级后的 UI
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// 你同样可以将错误日志上报给服务器
logErrorToMyService(error, errorInfo);
}
render() {
if (this.state.hasError) {
// 你可以自定义降级后的 UI 并渲染
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
捕获到错误之后的副作用是自定义的,上传服务器,或者用state
记录再显示在页面上:
componentDidCatch(error, errorInfo) {
// Catch errors in any components below and re-render with error message
this.setState({
error: error,
errorInfo: errorInfo
})
}
捕获处理
加上所有代码,将有问题的组件用错误边界的组件包裹起来,看看结果:
import { Component } from "react";
export default class ErrorTest extends Component {
render() {
return (
<div>
<ErrorBoundary>
<BugCounter></BugCounter>
</ErrorBoundary>
<span>my name is dan</span>
</div>
);
}
}
// Bug 报错组件
class BugCounter extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0,
};
}
click = () => {
this.setState(({ counter }) => ({ counter: counter + 1 }));
};
render() {
if (this.state.counter === 5) {
throw new Error("crashed!");
}
return (
<div>
<h3 onClick={this.click}>{this.state.counter}</h3>
</div>
);
}
}
// 错误边界处理组件
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染能够显示降级后的 UI
return { hasError: true };
}
render() {
if (this.state.hasError) {
// 你可以自定义降级后的 UI 并渲染
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
抛出异常在开发模式下依然是报错的,但是在使用yarn build
之后,再通过http-server
挂起来之后,访问生产的页面:
可以看到,虽然因为throw error
控制台出错,但是my name is dan
的显示并没有被影响,也就是说,错误边界内部的子组件错误没有影响到外部其他组件和元素。
作用范围
错误边界用于处理子组件生命周期和渲染函数上的错误,对于事件处理器,不会在渲染期间触发,对于事件处理器抛出的异常应该用try catch
。
错误边界无法捕获这些场景中的错误:
- 事件处理
- 异步代码
- 服务端渲染
- 错误边界自身抛出的错误(非子组件)
关于错误边界,一个 React
的官方demo
值得尝试:
https://codepen.io/gaearon/pen/wqvxGa?editors=0010
参考:
https://zh-hans.reactjs.org/docs/error-boundaries.html#how-about-event-handlers
https://zh-hans.reactjs.org/docs/react-component.html#static-getderivedstatefromerror
React 错误边界组件的更多相关文章
- Error Boundaries 错误边界
错误边界是用于捕获其子组件树 JavaScript 异常,记录错误并展示一个回退的 UI 的 React 组件,而不是整个组件树的异常.错误边界在渲染期间.生命周期方法内.以及整个组件树构造函数内捕获 ...
- 关于react16.4——错误边界
过去,组件内的 JavaScript 错误常常会破坏 React 内部状态,并导致它在下一次渲染时产生神秘的错误.这些错误总会在应用代码中较早的错误引发的,但 React 并没有提供一种方式能够在组件 ...
- 聊聊React高阶组件(Higher-Order Components)
使用 react已经有不短的时间了,最近看到关于 react高阶组件的一篇文章,看了之后顿时眼前一亮,对于我这种还在新手村晃荡.一切朝着打怪升级看齐的小喽啰来说,像这种难度不是太高同时门槛也不是那么低 ...
- React技巧之组件中返回多个元素
原文链接:https://bobbyhadz.com/blog/react-return-multiple-elements 作者:Borislav Hadzhiev 正文从这开始~ fragment ...
- React Native 之 组件化开发
前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会有所 ...
- React jQuery公用组件开发模式及实现
目前较为流行的react确实有很多优点,例如虚拟dom,单向数据流状态机的思想.还有可复用组件化的思想等等.加上搭配jsx语法和es6,适应之后开发确实快捷很多,值得大家去一试.其实组件化的思想一直在 ...
- React Native的组件ListView
React Native的组件ListView类似于iOS中的UITableView和UICollectionView,也就是说React Native的组件ListView既可以实现UITableV ...
- React Native交互组件之Touchable
React Native交互组件之Touchable:只要在组件外面包一个Touchable组件就可以实现点击交互. TouchableHighlight:高亮触摸 当点击时,组件的透明度会改变,可以 ...
- React中父组件与子组件之间的数据传递和标准化的思考
React中父组件与子组件之间的数据传递的的实现大家都可以轻易做到,但对比很多人的实现方法,总是会有或多或少的差异.在一个团队中,这种实现的差异体现了每个人各自的理解的不同,但是反过来思考,一个团队用 ...
随机推荐
- Linux in depth
Linux in depth bash file text editor filter selector command ?
- GoEasy使用阿里云OSS出现的问题
前言:本人使用goeasy来实现微信小程序里面和其他人的im临时对话窗口,想要实现可以同时发送语音和视频.图片.表情包的话,就要通过goeasy关联到阿里云的存储对象. 报错:The OSS Acce ...
- 10月份上线的NGK有什么不同之处?
近日,有小道消息传出公链项目NGK即将在10月上线的消息.各大社区纷纷开始布局,市场中关于NGK项目的消息也变得更多了起来.仅是社区热度这一点,对比之下就已经优于很多项目,那么是否还有其他优势呢?让我 ...
- java初学者必看之构造方法详细解读
java初学者必看之构造方法详细解读 构造方法是专门用来创建对象的方法,当我们通过关键字new来创建对象时,其实就是在调用构造方法. 格式 public 类名称(参数类型 参数名称){ 方法体 } 注 ...
- 02.Fancy Indexing
import numpy as np x = np.arange(16) index = [3,5,8] x[index] array([3, 5, 8]) X = x.reshape(4,-1) X ...
- 文件I/O的内核缓冲
本文转载自文件 I/O 的内核缓冲 导语 从最粗略的角度理解 Linux 文件 I/O 内核缓冲(buffer cache),啰嗦且不严谨.只为了直观理解. 当我们说一个程序读写磁盘上的文件时,通常指 ...
- 手把手教你Centos7 部署 gitlab社区版
一.前置说明: 操作系统:Centos 7 物理内存:>=2G 本人亲测,如果安装低版本的gitlab,比如我这里所使用的v8.17.0,物理内存1G,swap 2G虚拟内存即可部署.高版本的所 ...
- 1.代码规范之 if 语句编写
最近在看项目代码的时候, 看到需要判断的地方,出现了if的多重嵌套, 甚至是出现了十几层的嵌套, 代码的阅读性非常之差. 简单的举个例子(这里只是两层的嵌套): public class demo ...
- Spirng 循环依赖报错:Requested bean is currently in creation: Is there an unresolvable circular reference?
1:前言 最近在项目中遇到了一次循环依赖报错的问题,虽然解决的很快,但是有些不明白的地方,特此记录. 在此我把 bean 的结构和 注入方式单独拎出来进行演示 1.1:报错提示 1.2:错误日志 Ex ...
- 元类、orm
目录 一.内置函数exec 二.元类 1. 什么是元类 2. 元类的作用 3. 创建类的两种方法 4. 怎么自定义创建元类 三.ORM 1. ORM中可能会遇到的问题 2. ORM中元类需要解决的问题 ...