React 错误边界组件的处理

 更新时间:2021年04月12日 09:58:17   作者:xuxiaowei  
这篇文章主要介绍了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

https://zh-hans.reactjs.org/docs/react-component.html

https://codepen.io/gaearon/pen/wqvxGa?editors=0010

到此这篇关于React 错误边界组件的处理的文章就介绍到这了,更多相关React 错误边界内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • React Native自定义标题栏组件的实现方法

    React Native自定义标题栏组件的实现方法

    今天讲一下如何实现自定义标题栏组件,我们都知道RN有一个优点就是可以组件化,在需要使用该组件的地方直接引用并传递一些参数就可以了,这种方式确实提高了开发效率。对React Native自定义标题栏组件的实现方法感兴趣的朋友参考下
    2017-01-01
  • React如何将组件渲染到指定DOM节点详解

    React如何将组件渲染到指定DOM节点详解

    这篇文章主要给大家介绍了关于React如何将组件渲染到指定DOM节点的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习下吧。
    2017-09-09
  • React学习笔记之条件渲染(一)

    React学习笔记之条件渲染(一)

    条件渲染在React里就和js里的条件语句一样。下面这篇文章主要给大家介绍了关于React学习记录之条件渲染的相关资料,文中介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-07-07
  • React Hooks 实现和由来以及解决的问题详解

    React Hooks 实现和由来以及解决的问题详解

    这篇文章主要介绍了React Hooks 实现和由来以及解决的问题详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • React传值 组件传值 之间的关系详解

    React传值 组件传值 之间的关系详解

    这篇文章主要介绍了React传值 组件传值 之间的关系详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • React学习笔记之高阶组件应用

    React学习笔记之高阶组件应用

    这篇文章主要介绍了React 高阶组件应用,详细的介绍了什么是React高阶组件和具体使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-06-06
  • React Native实现简单的登录功能(推荐)

    React Native实现简单的登录功能(推荐)

    这篇文章主要介绍了React Native实现登录功能的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-09-09
  • React+Antd+Redux实现待办事件的方法

    React+Antd+Redux实现待办事件的方法

    这篇文章主要介绍了React+Antd+Redux实现待办事件的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • 想用好React的你必须要知道的一些事情

    想用好React的你必须要知道的一些事情

    现在最热门的前端框架,毫无疑问是 React 。下面这篇文章主要给大家分享了关于想用好React的你必须要知道的一些事情,文中介绍的非常详细,对大家具有一定参考学习价值,需要的朋友们下面来一起看看吧。
    2017-07-07
  • 简单的React SSR服务器渲染实现

    简单的React SSR服务器渲染实现

    这篇文章主要介绍了简单的React SSR服务器渲染实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-12-12

最新评论