React使用错误边界处理错误 – ReactJS实战教程

上一章ReactJS实战教程请查看:React Portal(插槽)用法全解
【React使用错误边界处理错误 – ReactJS实战教程】在过去,如果我们在组件中得到任何JavaScript错误,它会破坏React的内部状态,在接下来的渲染React状态将会比较难处理。React组件中没有处理这些错误的方法,也没有提供任何从中恢复的方法。但是,React 16引入了一个新概念,通过使用错误边界来处理错误。现在,如果在部分UI中发现任何JavaScript错误,它不会破坏整个应用程序。
错误边界是React组件,它捕捉应用程序中任何地方的JavaScript错误,记录这些错误,并显示备用UI。它不会破坏整个app组件树,只会在组件发生错误时呈现回退UI。错误边界捕获组件生命周期方法中呈现期间的错误,以及它们下面整个树的构造函数。
注意:
有时,在React应用程序中捕获错误边界是不可能的。这些都是:

  • 事件处理程序
  • 异步代码(例如setTimeout或requestAnimationFrame回调)
  • 服务器端渲染
  • 错误将在错误边界中抛出,而不是在其子边界中抛出。
对于简单的React应用程序,我们可以一次性声明一个错误边界,并将其用于整个应用程序。对于具有多个组件的复杂应用程序,我们可以声明多个错误边界来恢复整个应用程序的每个部分。
我们还可以向类似Rollbar的错误监视服务报告错误,此监视服务提供了跟踪有多少用户受到错误影响、查找错误原因并改进用户体验的能力。
类内的错误边界如果类组件定义了一个新的生命周期方法(静态getDerivedStateFromError()或componentDidCatch(error, info)),它就可能成为一个错误边界。我们可以使用静态的getDerivedStateFromError()在抛出错误时呈现回退UI,还可以使用componentDidCatch()来记录错误信息。
错误边界无法捕获其内部的错误。如果错误边界未能呈现错误消息,则错误将转到其上最近的错误边界。它类似于JavaScript中的catch{}块。
如何实现错误边界步骤1: 创建一个扩展React组件并在其类中传递props。
步骤2: 现在,添加componentDidCatch()方法,它允许你捕获树中它们下面的组件中的错误。
步骤3: 接下来添加render()方法,该方法负责如何呈现组件。例如,它将显示“Something is wrong”这样的错误消息。
例子
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // 它将更新状态,以便在下一个呈现中显示回退UI return { hasError: true }; } componentDidCatch(error, info) { // 它将捕获错误的任何组件如下。我们还可以将错误记录到错误报告服务中 logErrorToMyService(error, info); } render() { if (this.state.hasError) { return ( < div>Something is wrong.< /div>; ); } return this.props.children; } }

步骤4: 现在,我们可以将它作为常规组件使用,在HTML中添加你希望包含在错误边界中的新组件。在本例中,我们在MyWidgetCounter组件周围添加了一个错误边界。
< ErrorBoundary> < MyWidgetCounter/> < /ErrorBoundary>

在哪里放置错误边界?错误边界完全取决于你。你可以在应用程序组件的顶层使用错误边界,或者将其包装在各个组件上,以保护它们不破坏应用程序的其他部分。
让我们来看一个例子。
import React from 'react'; import './App.css'class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { error: false, errorInfo: null }; }componentDidCatch(error, errorInfo) { // 捕获下面任何组件中的错误,并使用错误消息重新渲染 this.setState({ error: error, errorInfo: errorInfo }) }render() { if (this.state.errorInfo) { 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> ); } 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 === 3) { throw new Error('I crashed!'); } return < h1 onClick={this.handleClick}>{this.state.counter}< /h1>; } }function App() { return ( < div> < p>< b>错误边界的例子< /b>< /p> < hr /> < ErrorBoundary> < p>这两个计数器位于相同的错误边界内< /p> < BuggyCounter /> < BuggyCounter /> < /ErrorBoundary> < hr /> < p>这两个计数器位于各自的错误边界内< /p> < ErrorBoundary>< BuggyCounter />< /ErrorBoundary> < ErrorBoundary>< BuggyCounter />< /ErrorBoundary> < /div> ); } export default App

在上面的代码片段中,当我们单击数字时,它会增加计数器。当计数器达到3时,程序会抛出错误,它模拟组件中的JavaScript错误。在这里,我们以两种方式使用误差边界,如下所示。
首先,这两个计数器位于相同的错误边界内,如果有人崩溃,错误边界将同时替换他们。
< ErrorBoundary> < BuggyCounter /> < BuggyCounter /> < /ErrorBoundary>

其次,这两个计数器位于各自的错误边界内。因此,如果有人崩溃,另一个就不会受到影响。
< ErrorBoundary>< BuggyCounter />< /ErrorBoundary> < ErrorBoundary>< BuggyCounter />< /ErrorBoundary>

未捕获错误的新行为这是与误差边界相关的一个重要含义。如果错误没有被任何错误边界捕获,将导致整个React应用程序的卸载。
事件处理程序中的错误边界错误边界不允许在事件处理程序中捕获错误。React不需要任何错误边界来从事件处理程序中的错误中恢复。如果需要在事件处理程序中捕获错误,可以使用JavaScript try-catch语句。
在下面的示例中,你可以看到事件处理程序将如何处理错误。
class MyComponent extends React.Component { constructor(props) { super(props); this.state = { error: null }; this.handleClick = this.handleClick.bind(this); }handleClick() { try { // 做一些会抛出错误的操作 } catch (error) { this.setState({ error }); } }render() { if (this.state.error) { return < h2>它捕获了一个错误.< /h2> } return < div onClick={this.handleClick}>点击< /div> } }

    推荐阅读