react进阶之异常处理机制-error Boundaries

该文章翻译自官网 https://reactjs.org/docs/error-boundaries.html

该文章包含以下内容:

1.Error Boundaries介绍

2.ComponentDidCatch 函数的参数

3.触发error boundaries后程序要走向哪里?

4.对于不能捕获的错误的新处理方式

5.在堆中跟踪component

6.try/catch 如何?

7.Event Handlers怎么样?

8.React 15后的函数命名改变


在过去,React组件中的js错误通常会污染React的内部state并且造成它发出一个让人难以理解的错误给下一个Render,我们在控制台看到的异常往往是由更内层的程序代码引起的,但是React并没有提供一个方式让我们在组件中优雅的解决他们并恢复业务逻辑。

Error Boundaries介绍


UI的某部分引起的JS错误不应该破坏整个程序,为了帮React的使用者解决这个问题,React 16介绍了一种关于错误边界(error boundary)的新观念。

error boundaries让react组件可以捕获在他们子级组件树任何地方的错误,并且打印出这些错误和演示一个预备UI(fallback UI),从而替换那些出现异常的组件树。Error boundaries在rendering,lifeCyclemethod或处于他们树层级之下的构造函数中捕获错误

(注释:lifecycle method是react固有名词,包括componentWillUpdate,componentWillReceiveProps,render等方法,这些方法会自动调用)

注意: error boundaries并不会捕捉这些错误:

1.事件处理器

2.异步代码

3.服务端的渲染代码

4.在error boundaries区域内的错误


在这个lifecycle method: componentDIdCatch(error,info) 里的类会变成一个 error boundary




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()方法像JS的catch{}模块一样工作,但是对于组件,只有class类型的组件(class component)可以成为一个error boundaries,在实际上,大多数情况下你可能只需要在整个程序中定义一个error boundary组件,然后你就可以一直使用它了!

请注意error boundaries仅仅可以捕获到在他们树的层级下面的错误,而不能捕获到本层级的错误,如果一个error boundaries渲染错误信息失败了,那么这个错误将会传播到一个在它层级上面,并且离它最近的error boundary 。这就像js的{}模块的工作机制一样。


ComponentDidCatch 参数

error: 这是一个已经被抛出的错误

info:这是一个componentStack key。这个属性有关于抛出错误的组件堆的信息

componentDidCatch(error, info) {
  
  /* Example stack information:
     in ComponentThatThrows (created by App)
     in ErrorBoundary (created by App)
     in div (created by App)
     in App
  */
  logComponentStackToMyService(info.componentStack);

触发error boundaries后程序要走向哪里?

关于error boundaries的后续处理由你做主,你可能会指定一个最高等级的路由组件去给用户标识某些地方出了问题,就像服务端的框架处理异常一样,你也可以指定一个在错误边界内的个人的小页面让整个程序不至于发生崩溃。


对于不能捕获的错误的新处理方式

这种变化有一个重要的新含义,对于React 16,没有被任何error boundary捕获的错误将会导致整个React组件树的崩溃。

我们对这个决定有争论,但是在我们的经验里,留下一个崩溃的UI界面比完全移除它要糟糕,例如,在一个产品比如聊天器中,留下一个崩坏的UI界面可能会导致某个人发送信息给一个并非他想要发送的人。同样的,对于一个支付类的app来说,不要显示任何东西显然比显示一个错误的金额数目要好。

这个改动意味着如果你迁移到React 16,你可能会发现一些以前没有注意到的,并且是确确实实存在的在你程序中的异常,增加error boundaries会让你在某些地方出现问题的时候可以提供更好的用户体验。


举个例子,facebook的侧边栏,信息面板,对话记录以及消息输入框处于被分割开来的error boundaries中,如果在他们的UI子组件中发生了崩溃事件,那么其他的组件还可以正常运行。

我们同样鼓励你使用JS 错误报道服务(或者你自己建立一个),然后你就可以了解到这些未被处理的异常是如何发生的,接着解决他们。

在堆中跟踪component


React 16 会把所有render过程中发生的错误打印给开发者,即使程序意外的包含了它。它不仅仅提供了错误信息和追踪js堆,也提供了组件的堆路径,现在你可以精确的看到组件树中错误发生的地方。
Error caught by Error Boundary component


你同样可以在组件的堆追踪中看到文件名字和行数,这是creat react app项目的默认配置
Error caught by Error Boundary component with line numbers

如果你没有使用Create React App ,你也可以通过添加这个插件,手动的管理你的babel配置。注意:它必须严格的限制在开发过程中使用,生产过程一定要剔除。

注意:
在堆的追踪中看到的组件名字取决于 Function.name属性。如果你想要支持那些现在还没有原生提供这些的浏览器和设备,比如ie11,consider including a Function.name polyfill in your bundled application, such as function.name-polyfill. 否则,你必须明确的在你所有的组件中都设置displayName.

try/catch 如何?

try/catch是非常棒的但是它只在imperative code(命令式代码)中起作用
try {
  showButton();
} catch (error) {
  // ...
}

然而,react组件是声明式的并且指定应该被渲染的内容

<Button />


Error boundaries保留了React的声明式性质,并且拥有你期待的表现。比如,即使通过某个在树的深层setState,在componentDidUpdate拦截中发生了错误,它也仍然会被正确的传送到最近的error boundary。

Event Handlers怎么样?

error boundaries并不能捕获event handles中的异常。

React并不需要error boundaries从event handles中恢复错误。与render方法和lifecycle拦截不同的是,event Handles并不会在rendering期间发生。所以如果他们被抛出,React仍然知道怎么去渲染。

如果你需要捕获event handler,使用普通的js代码try/catch 声明

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { error: null };
  }
  
  handleClick = () => {
    try {
      // Do something that could throw
    } catch (error) {
      this.setState({ error });
    }
  }

  render() {
    if (this.state.error) {
      return <h1>Caught an error.</h1>
    }
    return <div onClick={this.handleClick}>Click Me</div>
  }
}

注意以上代码仅仅展示通常的js习惯,而没有使用error boundaries。

React 15后的函数命名改变


React 15通过unstable_handleError方法 包含了一些有限的error boundaries支持。这个方法现在已经不能运用,你需要使用compoentDIdCatch。




没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试