react 错误边界_如何在React 16中使用错误边界

react 错误边界

Have you seen these in your console?

您是否在控制台中看到了这些?

Cannot read property ‘getHostNode’of null ?
TypeError: Cannot read property ‘_currentElement’ of null ?

If you maintain a React application, you know that this class of error messages can be among the most frustrating and difficult to resolve. Typical symptoms include stack traces that thread through dark regions of the React internals, devoid of hope or references to even a single line of your own code:

如果您维护一个React应用程序,您就会知道这类错误消息可能是最令人沮丧且难以解决的错误消息。 典型的症状包括堆栈跟踪 ,这些跟踪遍历了React内部的黑暗区域,没有希望,甚至没有引用到您自己的代码的一行:

TypeError: Cannot read property 'getHostNode' of null ?
  at getHostNode(~/react/lib/ReactReconciler.js:64:0)
  at getHostNode(~/react/lib/ReactCompositeComponent.js:383:0) ?
  at getHostNode(~/react/lib/ReactReconciler.js:64:0)
  at getHostNode(~/react/lib/ReactChildReconciler.js:114:0)?
  at updateChildren(~/react/lib/ReactMultiChild.js:215:0)
  at _reconcilerUpdateChildren(~/react/lib/ReactMultiChild.js:314:0)
  at _updateChildren(~/react/lib/ReactMultiChild.js:301:0)
  at updateChildren(~/react/lib/ReactDOMComponent.js:942:0)
  at _updateDOMChildren(~/react/lib/ReactDOMComponent.js:760:0) ?
  at updateComponent(~/react/lib/ReactDOMComponent.js:718:0)
  at receiveComponent(~/react/lib/ReactReconciler.js:126:0)
  at receiveComponent(~/react/lib/ReactCompositeComponent.js:751:0) ?
  at _updateRenderedComponent(~/react/lib/ReactCompositeComponent.js:721:0)
  at _performComponentUpdate(~/react/lib/ReactCompositeComponent.js:642:0)
  at updateComponent(~/react/lib/ReactCompositeComponent.js:544:0)
  at receiveComponent(~/react/lib/ReactReconciler.js:126:0) ?
  at receiveComponent(~/react/lib/ReactCompositeComponent.js:751:0)
  at _updateRenderedComponent(~/react/lib/ReactCompositeComponent.js:721:0)
  at _performComponentUpdate(~/react/lib/ReactCompositeComponent.js:642:0)
  at updateComponent(~/react/lib/ReactCompositeComponent.js:544:0)
  at receiveComponent(~/react/lib/ReactReconciler.js:126:0)  ?
  at receiveComponent(~/react/lib/ReactCompositeComponent.js:751:0)
  at _updateRenderedComponent(~/react/lib/ReactCompositeComponent.js:721:0)
  at _performComponentUpdate(~/react/lib/ReactCompositeComponent.js:642:0)
  at updateComponent(~/react/lib/ReactCompositeComponent.js:544:0) ?
  at receiveComponent(~/react/lib/ReactReconciler.js:126:0)
  at receiveComponent(~/react/lib/ReactCompositeComponent.js:751:0) ?
  at _updateRenderedComponent(~/react/lib/ReactCompositeComponent.js:721:0)
  at _performComponentUpdate(~/react/lib/ReactCompositeComponent.js:642:0)
  at updateComponent(~/react/lib/ReactCompositeComponent.js:558:0)
  at performUpdateIfNecessary(~/react/lib/ReactReconciler.js:158:0)
  at performUpdateIfNecessary(~/react/lib/ReactUpdates.js:151:0) ?
  at call(~/react/lib/Transaction.js:138:0)
  at call(~/react/lib/Transaction.js:138:0)
  at call(~/react/lib/ReactUpdates.js:90:0)
  at perform(~/react/lib/ReactUpdates.js:173:0)
  at call(~/react/lib/Transaction.js:204:0)
  at closeAll(~/react/lib/Transaction.js:151:0)
  at perform(~/react/lib/ReactDefaultBatchingStrategy.js:63:0) ?
  at batchedUpdates(~/react/lib/ReactUpdates.js:98:0)
  at batchedUpdates(~/react/lib/ReactEventListener.js:150:0)

If this type of stack trace from a React error is a familiar sight to you, I’ve got some good news for you!

如果您对React错误的这种堆栈跟踪类型感到熟悉,那么我对您来说有个好消息!

向React 16打个招呼 ( Say Hello to React 16 )

React 16 was officially released on September 26, 2017. React 16 is an API-compatible, under-the-hood rewrite of the React internals with ambitious goals like enabling asynchronous or preemptive rendering and providing new tools (with sweet names) for elegantly expressing component hierarchies, like fragments and portals, that are cumbersome today. Another goal of the architecture is handling errors with a new, more correct and rigorous strategy.

React 16于2017年9月26日正式发布。React16是一个兼容API的,对React内部的底层重写,其雄心勃勃的目标包括启用异步或抢占式渲染以及提供新工具(带有甜美名称)以优雅地表达如今,繁琐的组件层次结构(例如片段和门户)非常麻烦。 该体系结构的另一个目标是使用新的,更正确和严格的策略来处理错误。

This strategy means React 16 prevents situations where an error inside of a render call causes an invalid state and results in undefined behavior or confusing errors (like our good friend Cannot read property 'getHostNode' of null) by unmounting the entire component tree when errors are thrown inside render or lifecycle methods.

这种策略意味着React 16通过在错误发生时卸载整个组件树来防止渲染调用内部的错误导致无效状态并导致未定义的行为或令人困惑的错误(例如我们的好朋友Cannot read property 'getHostNode' of null )的情况。抛出在render或生命周期方法中。

Failing more aggressively on these errors means not allowing the application to continue running in a corrupted state — reducing the distance between where you trip (where the real problem occurs) and where you hit the ground (where React blows up because its internal bookkeeping is corrupt). This makes certain errors in React components easier to understand and fix.

无法更积极地解决这些错误,意味着不允许应用程序在损坏状态下继续运行-缩短行程(发生真正问题的地方)与触地(由于内部簿记损坏导致React崩溃)之间的距离)。 这使得React组件中的某些错误更容易理解和修复。

However, it also means that existing problems that may have been failing silently or non-catastrophically will now cause the entire app to unmount. Yikes!

但是,这也意味着可能已经静默或非灾难性地失败的现有问题现在将导致整个应用程序卸载。 kes!

The solution to this is React 16’s new tool for explicitly handling error propagation, error boundaries. Error boundaries are analogous to try{ }catch(e){ } statements, but they live inside and are scoped by component hierarchy instead of inside a given block of synchronous JavaScript.

解决方案是React 16的新工具,用于显式处理错误传播,错误边界。 错误边界类似于try{ }catch(e){ }语句,但是它们位于内部,并且受组件层次结构限制,而不是在给定的同步JavaScript块内。

Error boundaries exist because ↓↓↓ doesn’t work with the JSX rendering model:

存在错误边界是因为↓↓↓不适用于JSX渲染模型:

<div>
  { try {
    <CoolComplicatedComponent/>
  } catch(error){
    handleChildError(error)
    }
  }
</div>

By using error boundaries, you can isolate sections of your app’s component tree from errors in other sections, for instance, allowing your media player to continue running smoothly when the comment section crashes. This is without sacrificing React 16’s more predictable behavior or risking the possible exposure of corrupted state or undefined behavior. It’s a big improvement for your application’s stability.

通过使用错误边界,您可以将应用程序组件树的各个部分与其他部分中的错误隔离开,例如,当注释部分崩溃时,允许媒体播放器继续平稳运行。 这不会牺牲React 16的更可预测的行为,也不会冒可能暴露出损坏状态或未定义行为的风险。 这对您的应用程序的稳定性有很大的改进。

开始使用错误边界 ( Start Using Error Boundaries )

Error boundaries are something that every large React application should use to improve error resiliency. The API surface of error boundaries is simple: any React component becomes an error boundary when it implements the new lifecycle method, componentDidCatch(error, info). This will be called with any uncaught error that bubbles up from the component’s children’s lifecycle methods, constructors, or render methods (but not the component’s own errors).

错误边界是每个大型React应用程序都应使用的错误边界,以提高错误弹性。 错误边界的API表面很简单:任何React组件在实现新的生命周期方法componentDidCatch(error, info)时都会成为错误边界。 这将被任何未捕获的错误调用,该错误会从组件的子级生命周期方法,构造函数或渲染方法中冒出来(但不是组件自身的错误)。

<div>
  <ExampleBoundary>
    <h2>Sidebar</h2>
    <Widget/>
  </ExampleBoundary>
  <p> This content won't unmount when Widget throws. </p>
</div>

<ExampleBoundary> is a React component that implements componentDidCatch (there’s an example further below).

<ExampleBoundary>是一个实现componentDidCatch的React组件(下面还有一个示例)。

发现错误时该怎么办? ( What to do when you catch errors? )

You’re allowed to do whatever you see fit in componentDidCatch. But after it has been triggered, you can’t render this.props.children, and you must replace it with some sort of fallback UI. This fallback might mean rendering a heartfelt apology, a debug view, a feedback form, a link to support, or a funny GIF. It could also mean just discreetly rendering nothing at all — it depends on the needs of your application. Just do yourself a favor and try to ensure it’s not something that will throw its own errors!

您可以做任何您认为适合componentDidCatch事情。 但是,在触发它之后,您将无法呈现this.props.children ,并且必须使用某种后备UI替换它。 这种后退可能意味着渲染由衷的道歉,调试视图, 反馈表单 ,支持链接或有趣的GIF。 这也可能意味着仅谨慎地不渲染任何内容,这取决于应用程序的需求。 只是帮自己一个忙,并尝试确保它不会引发自己的错误!

example fallback UI

错误边界应该去哪里? (Where should Error Boundaries go?)

Error boundaries are an open-ended tool, and the community is still defining best practices for them. Our advice is to wrap components at the granularity they can be independently useful. This means that when one errors, the others can still accomplish their purpose. Wrapping your page content will protect your header or sidebar navigation components from being unmounted on an error and will give the user an easy way to back out and return to working parts of your application. By contrast, going to the extreme and wrapping every individual input component of a form could leave someone in a UI state that still responds to their input but can’t actually be used to finish their goal.

错误边界是一个开放式工具,社区仍在为它们定义最佳实践。 我们的建议是将组件包装成可以独立使用的粒度。 这意味着,当一个错误发生时,其他错误仍然可以实现其目的。 包装页面内容将保护您的标题或侧边栏导航组件免于因错误而被卸载,并使用户可以轻松地退出并返回到应用程序的工作部分。 相比之下,走极端并包装表单的每个单独的输入组件可能会使某人处于UI状态,该状态仍会响应他们的输入,但实际上不能用来完成他们的目标。

Note: by default, raven.js, Sentry’s JavaScript SDK, carefully instruments built-in methods to try to automatically wrap your code in try/catch blocks. It does this to attempt to capture error messages and stack traces from all your scripts, regardless of which origin they’re served from.

注意:默认情况下, SentryJavaScript SDK raven.js会谨慎地使用内置方法来尝试自动将代码包装在try / catch块中。 它这样做是为了尝试捕获所有脚本中的错误消息和堆栈跟踪信息,而不管它们来自何处。

将错误发送给Sentry! ( Send the errors to Sentry! )

Because error boundaries are analogous to try/catch, exceptions they capture will not automatically be bubbled up to Sentry’s global uncaught error handler in production. Make sure to call Raven.captureException(error) in your componentDidCatch implementations to get insights into these errors and fix them.

因为错误边界类似于try / catch, 所以捕获的异常不会自动冒泡到生产中Sentry的全局未捕获错误处理程序中 。 确保在componentDidCatch实现中调用Raven.captureException(error)以获得对这些错误的了解并进行修复。

Here’s an example of an error boundary component that apologizes and sends a report to Sentry plus gives the user the option to fill out a report of what happened:

这是一个错误边界组件的示例,该组件道歉并向Sentry发送报告,并为用户提供填写所发生情况的报告的选项:

class ExampleBoundary extends Component {
  constructor(props) {
    super(props);
    this.state = { error: null };
  }
  componentDidCatch(error, errorInfo) {
    this.setState({ error });
    Raven.captureException(error, { extra: errorInfo });
  }
  render() {
    if (this.state.error) {
      return (
        <div
          className="snap"
          onClick={() => Raven.lastEventId() && Raven.showReportDialog()}
        >
          <img src={oops} />
          <p>We're sorry — something's gone wrong.</p>
          <p>Our team has been notified, but click here fill out a report.</p>
        </div>
      );
    } else {
      //when there's not an error, render children untouched
      return this.props.children;
    }
  }
}

You can read (or fork!) the complete code here.

您可以在此处阅读(或分叉!) 完整的代码

One more cool aspect of componentDidCatch is the second argument, errorInfo. Currently, errorInfo has one property, componentStack, which is a component stack trace. That’s the path through your component tree from your application root all the way to the offending component — something that helps map the error location to your mental model and codebase. Because this information is helpful for triaging and resolving errors, we recommend sending it with Sentry errors as extra data.

componentDidCatch的另一个errorInfo方面是第二个参数errorInfo 。 当前, errorInfo具有一个属性componentStack ,这是一个组件堆栈trace 。 这就是从应用程序根目录到有问题的组件的整个组件树的路径,这有助于将错误位置映射到您的思维模型和代码库。 因为此信息有助于分类和解决错误,所以我们建议将其与Sentry错误一起作为额外数据发送。

componentStack as seen in Sentry

As always, you can try Sentry for your React app (it’s 100% open source, too).

与往常一样,您可以为您的React应用尝试Sentry (它也是100%开放源代码)。

That’s it! Happy error monitoring.

而已! 快乐的错误监控

翻译自: https://scotch.io/tutorials/how-to-use-error-boundaries-in-react-16

react 错误边界

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值