在构建应用时,错误是不可避免的。即使采用最佳的代码实践,运行时也可能会出现意外错误,导致应用崩溃。因此,处理错误是非常重要的。本文就来看看如何在 React 中捕获和处理错误,以及更强大的 React 错误处理方式!
当在React应用程序中处理错误时,你可以采取以下几种方法:
try-catch
在使用JavaScript时,可以使用try-catch块来捕获和处理错误。你可以将可能引发错误的代码放在try块中,并在catch块中处理异常情况。例如:
js
try {
// 可能引发错误的代码
} catch (error) {
// 处理错误
}
try...catch仅适用于命令式代码,例如数据获取;而不是适用于声明式代码
,例如在组件中编写的 JSX 就是声明式代码。那该如何在 React 中捕获错误呢?在 React 16 中,引入了一个新概念:React Error Boundary。下面来看一下它是什么,以及如何使用。
Error Boundary
React Error Boundary (错误边界)
是 React 应用中错误处理的一种方式。它是一个 React 组件,可以捕获子组件树中任何位置的 JavaScript 错误,并记录这些错误,显示一个备选 UI,而不是一个崩溃的组件树(白屏)。它们就像一个 JavaScript 的 catch {} 块,但是只针对组件。
我们可以在整个应用范围内设置错误边界,也可以在各个组件上进行更细粒度的控制。需要注意的是,错误边界只会捕获渲染时、生命周期方法和构造函数中的错误,但不会捕获以下错误:
事件处理
(对于这种情况,需要使用常规的 try/catch 块)异步代码
(例如,setTimeout 或 requestAnimationFrame 回调函数)服务端渲染
错误发生在错误边界本身而不是其子组件中时
错误边界是在 React v16 中引入的,要使用错误边界,需要定义一个类组件,并添加以下生命周期方法之一或两个:
getDerivedStateFromError()
: 这个生命周期方法在错误抛出后渲染备选 UI。它在渲染阶段被调用,所以不允许有副作用。componentDidCatch()
: 这个方法用于记录错误信息。它在提交阶段被调用,所以可以执行副作用。
下面来看一个 ErrorBoundary 类组件的例子,它实现了 getDerivedStateFromError() 和 componentDidCatch() 生命周期方法:
jsx
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// 更新 state,下一次渲染将展示备选 UI。
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
console.log(error, errorInfo);
}
render() {
if (this.state.hasError) {
// 可以渲染任意自定义的备选 UI
return <h1>出错啦!</h1>;
}
return this.props.children;
}
}
// 在组件中使用
class App extends React.Component {
render() {
return (
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
);
}
}
这里定义了一个名为ErrorBoundary
的错误边界组件。它的构造函数初始化了状态对象,并设置 hasError 属性为 false,表示当前没有发生错误。
getDerivedStateFromError()
方法在捕获到错误时会被调用。它接收一个 error 对象作为参数,并返回一个新的状态对象,将 hasError 属性设置为 true,以便在下一次渲染时展示备选的 UI。componentDidCatch()
方法在捕获到错误后会被调用。在这个例子中,将错误和错误信息输出到控制台。
在 render() 方法中,根据 hasError 的值来决定渲染原始子组件还是备选的 UI。如果 hasError 为 true,则渲染 <h1>出错啦!</h1>
,否则渲染原始子组件。在组件中使用错误边界时,将需要进行错误边界保护的组件包裹在 组件中即可。
在React组件中,我们可以使用 Error Boundary 来包裹任何组件,这样就不会因为一个小组件的崩溃,而导致整个组件崩溃,致使出现白屏。只有出现错误的组件处不能正常渲染,而是渲染备选 UI。也方便我们快速查找是哪个组件出了问题。
react-error-boundary
react-error-boundary
是一个由社区维护的 React 错误边界工具,它简化了在 React 应用中实现错误边界的过程。使用react-error-boundary
可以更加方便地捕获和处理组件树中的错误。
通过 react-error-boundary
,你可以使用一个高阶组件 ErrorBoundary
来包装你的组件,并在需要时处理错误。它提供了一些灵活的方式来定义错误处理行为,以及在错误发生时展示备用 UI。与手动实现错误边界相比,使用 react-error-boundary
可以减少重复代码,并提供更清晰的 API。
react-error-boundary
提供了一些可用于自定义行为和处理错误的 props。以下是它的一些主要 props:
FallbackComponent
:用于指定一个自定义组件,在错误边界内发生错误时进行渲染。它提供了灵活性,可以创建一个视觉上吸引人且信息丰富的用户界面来显示错误,并提供任何必要的操作。fallbackRender
:类似于 FallbackComponent,该属性用于定义一个自定义的渲染函数来渲染错误回退界面。它提供了对渲染过程的更多控制,并允许进行更高级的错误处理逻辑。onError
:其接受一个回调函数,在错误边界捕获到错误时调用该函数,并传递错误对象和组件堆栈跟踪信息。它使我们能够执行额外的操作,例如记录错误或将错误报告发送到外部服务。onReset
:其接受一个回调函数,在错误边界成功重置后触发。它可以用于执行清理操作或在错误恢复后更新组件的状态。fallbackProps
:允许向 FallbackComponent 或 fallbackRender 函数传递额外的 props。它可以用于提供上下文或附加数据给错误回退界面。retry
:布尔值,确定错误边界是否允许重试导致错误的操作。当设置为 true 时,resetErrorBoundary 函数可以从错误回退界面中调用以重试操作。
以下是一个简单的示例,展示了如何使用 react-error-boundary
:
jsx
import React from 'react';
import { ErrorBoundary } from 'react-error-boundary';
// 自定义错误 UI 组件
function ErrorFallback({ error, resetErrorBoundary }) {
return (
<div>
<h2>Something went wrong:</h2>
<pre>{error.message}</pre>
<button onClick={resetErrorBoundary}>Try again</button>
</div>
);
}
// 需要进行错误边界处理的组件
function MyComponent({ shouldThrowError }) {
if (shouldThrowError) {
throw new Error('Error thrown from MyComponent');
}
return <h1>Hello, World!</h1>;
}
function App() {
return (
<ErrorBoundary
FallbackComponent={ErrorFallback} // 指定错误时展示的 UI 组件
onReset={() => console.log('Error boundary reset!')} // 定义重置错误边界时的回调函数
onError={(error, info) => console.log('Error caught by error boundary:', error, info)} // 定义捕获错误时的回调函数
>
<MyComponent shouldThrowError={true} />
</ErrorBoundary>
);
}
export default App;
在这个示例中,我们使用 ErrorBoundary
组件包装了 MyComponent
组件,并指定了在错误发生时展示的备用 UI 组件 ErrorFallback
。我们还可以通过 onReset
和 onError
属性来定义错误边界的行为。