React DocsTutorialCommunity Blog v16.0.0-rc.3GitHub
React16的错误处理
2017.9.26 由Dan Abramov撰写。
随着React16的发布越来越接近,我们想宣布一些关于在组件内如何处理JavaScript错误的变化。这些变化包括在React16 Beta版本,并将会成为React16的一部分。
顺便说一句, 我们刚刚发布了第一个React16 beta让你尝试!
React15和更早版本中的行为
在过去,组件内部的JavaScript错误会破坏React的内部状态,并导致它在下一步的渲染中触发神秘错误 。这些错误经常是由代码中早期的错误引起的,但是React并没有提供一种在组件中优雅地处理它们的方法,并且无法从它们中恢复过来。
引入错误边界
UI部分的一个JavaScript错误不应该破坏整个程序。为了给React用户解决这个问题,React16引入了“错误边界”的新概念。
错误边界是在他们的子组件树中捕捉JavaScript错误,记录这些错误,并显示一个回退UI的React组件,而不是崩溃的组件树。错误边界捕捉渲染过程中、生命周期方法中以及它们下面整个树的构造函数中的错误。
如果一类组件定义了一个新的生命周期方法componentDidCatch(error, info)
,那么这类组件就成为一个错误边界:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, info) {
// 显示回退UI
this.setState({ hasError: true });
// 你也可以把错误信息上报给错误上报服务器
logErrorToMyService(error, info);
}
render() {
if (this.state.hasError) {
// 你可以渲染任何自定义的回退UI
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
然后就可以作为常规组件使用它:
<ErrorBoundary>
<MyWidget />
</ErrorBoundary>
这个componentDidCatch()
方法就像JavaScript中的 catch {}
块,但它是应用于组件上的。只有组件类可以成为错误边界。实际上,大多数情况下您希望声明一次错误边界组件,并在整个应用程序中使用它。
注意,错误边界只能捕获树结构中它下面组件中的错误。一个错误边界不能捕获它本身的错误。如果错误边界捕获错误失败,则错误将传播到上面最接近的错误边界。这也类似于JavaScript中catch {}
块的工作原理。
在线演示
查看这个声明的例子和使用错误边界与React 16 beta一起。
在哪里放置错误边界
错误边界的粒度取决于您。您可以包装顶层路由组件来向用户显示“出错”消息,就像服务器端框架经常处理崩溃一样。您还可以将单个小组件封装在错误边界中,以保护它们不致破坏应用程序的其余部分。
针对未捕获错误的新行为
这一变化具有重要意义。对于React16,没有被任何错误边界捕获的错误将导致整个React组件树的卸载。
我们讨论了这个决定,但根据我们的经验,把损坏的UI留下比彻底删除更糟糕。例如,在像Messenger这样的产品中,留下破损的UI可能导致某人向错误的人发送消息。同样,对于一个支付应用程序显示错误的金额比什么都不渲染要坏。
这种变化意味着,当您迁移到React16时,您可能会发现以前应用程序中没有注意到的错误崩溃。添加错误边界,可以在出错时,提供更好的用户体验。
例如,Facebook Messenger将边栏、信息面板、会话日志和消息输入的内容封装到不同的错误边界中。如果某个UI区域中的某个组件崩溃,剩下的部分仍然保持交互。
我们也鼓励您使用JS错误上报服务(或建立您自己的),您可以了解他们在生产中发生的未处理的异常,并修复。
组件的堆栈跟踪
在开发过程中,React16会将渲染过程中发生的所有错误打印到控制台,即使应用程序意外地将它们删除。除了错误消息和JavaScript的栈,它也提供了组件的堆栈跟踪。现在你可以精确地看到在组件树的哪部分发生了错误:
你也可以看到文件名和行号在组件堆栈跟踪中。这在Create React App脚手架中是默认的:
如果你不使用Create React App,你可以添加这个插件手动修改你的Babel配置。请注意,它只是为了在开发过程中使用,在生产环境一定要禁止。
为什么不用try
/ catch
?
try
/ catch
很伟大,但是它只适用于必要的代码:
try {
showButton();
} catch (error) {
// ...
}
然而,React组件是声明和指定什么内容应该呈现:
`<Button />`
错误边界保留了React的声明性,并按您预期的方式运行。例如,即使一个错误发生在componentDidUpdate
,但是它是由组件树深处的某个setState
造成的,它仍然会正确地传播到最近的错误边界。
从React15命名更改
React15包含一个对错误边界支持很有限的方法,它有一个不同的名字:unstable_handleError
。这种方法不再工作,从最初的16 beta版本开始,您需要在代码中把它改为componentDidCatch
。
对于这种变化,我们提供了a codemod来自动迁移您的代码。
最近的文章
- React v16.0
- DOM Attributes in React 16
- Error Handling in React 16
- React v15.6.0
- What's New in Create React App
- React v15.5.0
- React v15.4.0
- Our First 50,000 Stars
- Relay: State of the State
- Create Apps with No Configuration
- All posts ...
React16错误处理相关文章:Quick StartThinking in ReactTutorial Advanced GuidesCommunityStack OverflowDiscussion Forum Reactiflux ChatFacebook TwitterResourcesConferencesVideos Examples Complementary ToolsMoreBlogGitHub React NativeAcknowledgements
Copyright © 2017 Facebook Inc.