如何在功能性 React 组件中使用错误边界?

问题描述 投票:0回答:8

我可以通过实现 componentDidCatch,在 React 中

使类成为错误边界

是否有一种干净的方法可以将功能组件设置为错误边界而不将其转换为类?

或者这是代码味道?

reactjs error-handling
8个回答
119
投票

从 v16.2.0 开始,无法将功能组件转变为错误边界。

React 文档对此很清楚,尽管您可以随意重复使用它们:

componentDidCatch()
方法的工作方式类似于 JavaScript
catch {}
块,但适用于组件。 只有类组件可以作为错误边界。在实践中,大多数时候您需要声明一次错误边界组件并在整个应用程序中使用它。

另请记住,

try/catch
不适用于所有情况
如果层次结构深处的组件尝试更新并失败,则父级之一中的
try/catch
块将不起作用 - 因为它不一定与子级一起更新。


26
投票

正如已经提到的,React 团队尚未实现等效的钩子,并且钩子实现没有发布时间表

npm 上的一些第三方包实现了错误边界挂钩。我发布了 react-use-error-boundary,尝试重新创建一个类似于 Preact useErrorBoundary 的 API:

import { withErrorBoundary, useErrorBoundary } from "react-use-error-boundary"; const App = withErrorBoundary(({ children }) => { const [error, resetError] = useErrorBoundary( // You can optionally log the error to an error reporting service (error, errorInfo) => logErrorToMyService(error, errorInfo) ); if (error) { return ( <div> <p>{error.message}</p> <button onClick={resetError}>Try again</button> </div> ); } return <div>{children}</div>; });
    

25
投票
有一个实现可以处理功能组件不存在的功能,例如

componentDidCatch

deriveStateFromError

据作者介绍,它是基于React.memo()的。

所提出的解决方案深受新的 React.memo() API 的启发。

import Catch from "./functional-error-boundary" type Props = { children: React.ReactNode } const MyErrorBoundary = Catch(function MyErrorBoundary(props: Props, error?: Error) { if (error) { return ( <div className="error-screen"> <h2>An error has occured</h2> <h4>{error.message}</h4> </div> ) } else { return <React.Fragment>{props.children}</React.Fragment> } })
参考和 API 

这里


17
投票
我所做的是创建自定义

class component

 并将我的 
functional/class
 组件包装在其中需要的地方。这就是我的自定义类组件的样子:

class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = {error: ""}; } componentDidCatch(error) { this.setState({error: `${error.name}: ${error.message}`}); } render() { const {error} = this.state; if (error) { return ( <div>{error}</div> ); } else { return <>{this.props.children}</>; } } }
并像这样使用我的

functional/class

组件:

<ErrorBoundary key={uniqueKey}> <FuncationalOrChildComponent {...props} /> </ErrorBoundary>
PS:像往常一样, key 属性非常重要,因为如果您有动态子元素,它将确保重新渲染 

ErrorBoundary

 组件。


13
投票
React 官方团队未提供对功能组件的错误边界支持。 我们可以使用 npm 包实现功能组件的错误边界。

https://www.npmjs.com/package/react-error-boundary


3
投票
有一些很棒的第三方库可以实现此目的,但如果您已经在使用 Sentry,那么您可以使用

Sentry.ErrorBoundary


文档

import React from "react"; import * as Sentry from "@sentry/react"; <Sentry.ErrorBoundary fallback={<p>An error has occurred</p>}> <Example /> </Sentry.ErrorBoundary>;
或作为高阶组件

import React from "react"; import * as Sentry from "@sentry/react"; Sentry.withErrorBoundary(Example, { fallback: <p>an error has occurred</p> });
    

3
投票
如果您在 2023 年访问此页面,正在使用 TypeScript 并且不想实现依赖项,Netlify 上有一个非常简单但有效的示例,说明如何实现简单的错误边界。

遗憾的是,根据反应文档,仍然没有解决该问题的功能性解决方案。

Netlify 示例:

https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/error_boundaries/


0
投票
import React, { useState, useEffect } from 'react'; import { Button } from 'antd'; const ErrorBoundary = ({ children }) => { const [hasError, setHasError] = useState(false); useEffect(() => { const errorHandler = (event) => { setHasError(true); console.error("ErrorBoundary caught an error", event.error); }; window.addEventListener("error", errorHandler); window.addEventListener("unhandledrejection", errorHandler); return () => { window.removeEventListener("error", errorHandler); window.removeEventListener("unhandledrejection", errorHandler); }; }, []); if (hasError) { return ( <div style={styles.container}> <div style={styles.errorBox}> <h1 style={styles.title}>Oops! Something went wrong.</h1> <p style={styles.message}> We're sorry for the inconvenience. Please try again later or contact support if the issue persists. </p> <Button type="primary" style={styles.button}> <a href="/profile">GO BACK</a> </Button> </div> </div> ); } return children; }; const styles = { container: { display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh', backgroundColor: '#f0f2f5', }, errorBox: { textAlign: 'center', backgroundColor: '#fff', padding: '40px', borderRadius: '8px', boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)', }, title: { fontSize: '24px', color: '#ff4d4f', }, message: { fontSize: '16px', color: '#595959', marginBottom: '20px', }, button: { marginTop: '20px', }, }; export default ErrorBoundary;
您可以使用这个基于功能的错误边界组件

© www.soinside.com 2019 - 2024. All rights reserved.