详解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 相关文章推荐
jQuery Lightbox 图片展示插件使用说明
Apr 25 Javascript
js实现图片轮换效果代码
Apr 16 Javascript
jQuery setTimeout传递字符串参数报错的解决方法
Jun 09 Javascript
jQuery操作DOM之获取表单控件的值
Jan 23 Javascript
基于jquery实现的仿优酷图片轮播特效代码
Jan 13 Javascript
Highcharts 多个Y轴动态刷新数据的实现代码
May 28 Javascript
解决微信浏览器Javascript无法使用window.location.reload()刷新页面
Jun 21 Javascript
详解如何用模块化的方式写vuejs
Dec 16 Javascript
JavaScript实现元素滚动条到达一定位置循环追加内容
Dec 28 Javascript
Vue 菜单栏点击切换单个class(高亮)的方法
Aug 22 Javascript
浅谈vue引用静态资源需要注意的事项
Sep 28 Javascript
vue动态渲染svg、添加点击事件的实现
Mar 13 Javascript
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
php实现的仿阿里巴巴实现同类产品翻页
2009/12/11 PHP
深入Memcache的Session数据的多服务器共享详解
2013/06/13 PHP
PHP上传文件时文件过大$_FILES为空的解决方法
2013/11/26 PHP
PHP处理SQL脚本文件导入到MySQL的代码实例
2014/03/17 PHP
JSON PHP中,Json字符串反序列化成对象/数组的方法
2018/05/31 PHP
php设计模式之模板模式实例分析【星际争霸游戏案例】
2020/03/24 PHP
extjs render 用法介绍
2013/09/11 Javascript
JavaScript var声明变量背后的原理示例解析
2013/10/12 Javascript
简体中文转换繁体中文(实现代码)
2013/12/25 Javascript
谈谈JavaScript自定义回调函数
2015/10/18 Javascript
JS两个数组比较,删除重复值的巧妙方法(推荐)
2016/06/03 Javascript
AngularJS控制器controller给模型数据赋初始值的方法
2017/01/04 Javascript
基于daterangepicker日历插件使用参数注意的问题
2017/08/10 Javascript
webpack处理 css\less\sass 样式的方法
2017/08/21 Javascript
JS点击图片弹出文件选择框并覆盖原图功能的实现代码
2017/08/25 Javascript
jQuery实现简单的Ajax调用功能示例
2019/02/15 jQuery
node.js使用express框架进行文件上传详解
2019/03/03 Javascript
详解express使用vue-router的history踩坑
2019/06/05 Javascript
Vue 使用beforeEach实现登录状态检查功能
2019/10/31 Javascript
vue.config.js常用配置详解
2019/11/14 Javascript
多个Vue项目部署到服务器的步骤记录
2020/10/22 Javascript
Python记录详细调用堆栈日志的方法
2015/05/05 Python
Python使用SocketServer模块编写基本服务器程序的教程
2016/07/12 Python
Python列表和元组的定义与使用操作示例
2017/07/26 Python
Python模拟三级菜单效果
2017/09/11 Python
Matplotlib中文乱码的3种解决方案
2018/11/15 Python
python使用zip将list转为json的方法
2018/12/31 Python
python matplotlib实现将图例放在图外
2020/04/17 Python
澳大利亚手袋、珠宝和在线时尚精品店:The Way
2019/12/21 全球购物
澳大利亚最受欢迎的超级商场每日优惠:Catch
2020/11/17 全球购物
Agoda中文官网:安可达(低价预订全球酒店)
2021/01/18 全球购物
白岩松演讲
2014/05/21 职场文书
大学生毕业求职信
2014/06/12 职场文书
超市采购员岗位职责
2015/04/07 职场文书
旅行社计调工作总结
2015/08/12 职场文书
曾国藩励志经典名言37句,蕴含哲理
2019/10/14 职场文书