详解React 16 中的异常处理


Posted in Javascript onJuly 28, 2017

详解React 16 中的异常处理

异常处理

在 React 15.x 及之前的版本中,组件内的异常有可能会影响到 React 的内部状态,进而导致下一轮渲染时出现未知错误。这些组件内的异常往往也是由应用代码本身抛出,在之前版本的 React 更多的是交托给了开发者处理,而没有提供较好地组件内优雅处理这些异常的方式。在 React 16.x 版本中,引入了所谓 Error Boundary 的概念,从而保证了发生在 UI 层的错误不会连锁导致整个应用程序崩溃;未被任何异常边界捕获的异常可能会导致整个 React 组件树被卸载。所谓的异常边界即指某个能够捕获它的子元素(包括嵌套子元素等)抛出的异常,并且根据用户配置进行优雅降级地显示而不是导致整个组件树崩溃。异常边界能够捕获渲染函数、生命周期回调以及整个组件树的构造函数中抛出的异常。

我们可以通过为某个组件添加新的 componentDidCatch(error, info) 生命周期回调来使其变为异常边界:

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>
<MyWidget />
</ErrorBoundary>

componentDidCatch() 方法就好像针对组件的 catch {} 代码块;不过 JavaScript 中的 try/catch 模式更多的是面向命令式代码,而 React 组件本身是声明式模式,因此更适合采用指定渲染对象的模式。需要注意的是仅有类组件可以成为异常边界,在真实的应与开发中我们往往会声明单个异常边界然后在所有可能抛出异常的组件中使用它。另外值得一提的是异常边界并不能捕获其本身的异常,如果异常边界组件本身抛出了异常,那么会冒泡传递到上一层最近的异常边界中。

在真实地应用开发中有的开发者也会将崩坏的界面直接展示给开发者,不过譬如在某个聊天界面中,如果在出现异常的情况下仍然直接将界面展示给用户,就有可能导致用户将信息发送给错误的接受者;或者在某些支付应用中导致用户金额显示错误。因此如果我们将应用升级到 React 16.x,我们需要将原本应用中没有被处理地异常统一包裹进异常边界中。譬如某个应用中可能会分为侧边栏、信息面板、会话界面、信息输入等几个不同的模块,我们可以将这些模块包裹进不同的错误边界中;这样如果某个组件发生崩溃,会被其直属的异常边界捕获,从而保证剩余的部分依然处于可用状态。同样的我们也可以在异常边界中添加错误反馈等服务接口以及时反馈生产环境下的异常并且修复他们。完整的应用代码如下所示:

class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { error: null, errorInfo: null };
 }

 componentDidCatch(error, errorInfo) {
  // Catch errors in any components below and re-render with error message
this.setState({
   error: error,
   errorInfo: errorInfo
  })
  // You can also log error messages to an error reporting service here
 }

 render() {
if (this.state.errorInfo) {
   // Error path
return (
    <div>
     <h2>Something went wrong.</h2>
     <details style={{ whiteSpace: 'pre-wrap' }}>
      {this.state.error && this.state.error.toString()}
      <br />
      {this.state.errorInfo.componentStack}
     </details>
    </div>
   );
  }
  // Normally, just render children
return this.props.children;
 } 
}

class BuggyCounter extends React.Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
 }

 handleClick() {
this.setState(({counter}) => ({
   counter: counter + 1
  }));
 }

 render() {
if (this.state.counter === 5) {
   // Simulate a JS error
throw new Error('I crashed!');
  }
return <h1 onClick={this.handleClick}>{this.state.counter}</h1>;
 }
}

function App() {
return (
  <div>
   <p>
    <b>
     This is an example of error boundaries in React 16.
     <br /><br />
     Click on the numbers to increase the counters.
     <br />
     The counter is programmed to throw when it reaches 5. This simulates a JavaScript error in a component.
    </b>
   </p>
   <hr />
   <ErrorBoundary>
    <p>These two counters are inside the same error boundary. If one crashes, the error boundary will replace both of them.</p>
    <BuggyCounter />
    <BuggyCounter />
   </ErrorBoundary>
   <hr />
   <p>These two counters are each inside of their own error boundary. So if one crashes, the other is not affected.</p>
   <ErrorBoundary><BuggyCounter /></ErrorBoundary>
   <ErrorBoundary><BuggyCounter /></ErrorBoundary>
  </div>
 );
}



ReactDOM.render(
 <App />,
 document.getElementById('root')
);

以上就是详解React 16 中的异常处理的资料整理,如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

Javascript 相关文章推荐
收集的网上用的ajax之chat.js文件
Apr 08 Javascript
UI Events 用户界面事件
Jun 27 Javascript
用JavaScript实现动画效果的方法
Jul 20 Javascript
js实现按Ctrl+Enter发送效果
Sep 18 Javascript
jquery实现侧边弹出的垂直导航
Dec 09 Javascript
jQuery中[attribute=value]选择器用法实例
Dec 31 Javascript
node.js调用C++开发的模块实例
Jul 03 Javascript
jQuery插件windowScroll实现单屏滚动特效
Jul 14 Javascript
微信小程序实现图片上传放大预览删除代码
Jun 28 Javascript
解决Layui数据表格的宽高问题
Sep 28 Javascript
JavaScript实现简易聊天对话框(加滚动条)
Feb 10 Javascript
Vue 实现可视化拖拽页面编辑器
Feb 01 Vue.js
JavaScript截屏功能的实现代码
Jul 28 #Javascript
BootStrap selectpicker后台动态绑定数据的方法
Jul 28 #Javascript
详解angularjs的数组传参方式的简单实现
Jul 28 #Javascript
js 获取html5的data属性实现方法
Jul 28 #Javascript
jQuery获取table表中的td标签(实例讲解)
Jul 28 #jQuery
浅谈JS中的常用选择器及属性、方法的调用
Jul 28 #Javascript
js原生代码实现轮播图的实例讲解
Jul 28 #Javascript
You might like
在windows平台上构建自己的PHP实现方法(仅适用于php5.2)
2013/07/05 PHP
PHP多进程通信-消息队列使用
2019/03/08 PHP
7个Javascript地图脚本整理
2009/10/20 Javascript
javascript写的一个链表实现代码
2009/10/25 Javascript
JQuery跨Iframe选择实现代码
2010/08/19 Javascript
jquery each()源代码
2011/02/14 Javascript
前台js对象在后台转化java对象的问题探讨
2013/12/20 Javascript
jquery序列化表单去除指定元素示例代码
2014/04/10 Javascript
jQuery焦点图轮播特效代码分享(3款)
2015/09/05 Javascript
js判断手机访问或者PC的几个例子(常用于手机跳转)
2015/12/15 Javascript
JS键盘版计算器的制作方法
2016/12/03 Javascript
微信小程序实现image组件图片自适应宽度比例显示的方法
2018/01/16 Javascript
angularjs 页面自适应高度的方法
2018/01/17 Javascript
vue数据传递--我有特殊的实现技巧
2018/03/20 Javascript
vue-cli 目录结构详细讲解总结
2019/01/15 Javascript
Vue开发之封装上传文件组件与用法示例
2019/04/25 Javascript
vue.js表单验证插件(vee-validate)的使用教程详解
2019/05/23 Javascript
微信小程序使用Vant Weapp组件库的方法步骤
2019/08/01 Javascript
vuex管理状态 刷新页面保持不被清空的解决方案
2019/11/11 Javascript
JS如何判断对象是否包含某个属性
2020/08/29 Javascript
vue实现简单计算商品价格
2020/09/14 Javascript
解决vue props传Array/Object类型值,子组件报错的情况
2020/11/07 Javascript
如何解决django配置settings时遇到Could not import settings 'conf.local'
2014/11/18 Python
在Python的Flask框架下收发电子邮件的教程
2015/04/21 Python
基于并发服务器几种实现方法(总结)
2017/12/29 Python
Python中py文件引用另一个py文件变量的方法
2018/04/29 Python
深入理解python中sort()与sorted()的区别
2018/08/29 Python
python 画三维图像 曲面图和散点图的示例
2018/12/29 Python
Python3交互式shell ipython3安装及使用详解
2020/07/11 Python
Ivory Isle Designs美国/加拿大:婚礼和活动文具公司
2018/08/21 全球购物
英国地毯卖家:The Rug Seller
2019/07/18 全球购物
澳大利亚当地社区首选的光学商店:1001 Optical
2019/08/24 全球购物
银行批评与自我批评
2014/02/10 职场文书
小学校本培训方案
2014/06/06 职场文书
晚会闭幕词
2015/01/28 职场文书
2016年春季运动会广播稿
2015/08/19 职场文书