React ErrorBoundary 无法捕获“无法读取未定义的属性”

发布于 2025-01-17 08:25:07 字数 1095 浏览 0 评论 0原文

我在使用 React ErrorBoundary 时遇到了一个奇怪的边缘情况。如果异常发生在内联表达式中,则不会被处理。例如:

const page = webtexts[courseId].pages[pageFamilyId]; // Returns undefined
...
<ErrorBoundary>
    // "Cannot read properties of undefined (reading 'page_name')" won't be processed in ErrorBoundary
    <span>{page.page_name}</span>
</ErrorBoundary>

但是如果我将组件中有问题的地方包裹起来,它就可以正常工作。

const page = webtexts[courseId].pages[pageFamilyId]; // Returns undefined
...
const WrapFailingPage: React.FC<{ page: any }> = ({ page }) => {
    return <span>{page.page_name}</span>;
};
...
<ErrorBoundary>
    <WrapFailingPage page={page} /> // The error is properly processed in ErrorBoundary
</ErrorBoundary>

对于演示,我制作了一个简单的 Codepen - https://codepen.io/OlexanderD/pen/wvpdpxY< /a>.

ErrorBoundary 应该这样做吗?为什么内联表达式可能会出现问题?

I faced a weird edge case with React ErrorBoundary. Exceptions are not being processed if they happen in inline expression. For example:

const page = webtexts[courseId].pages[pageFamilyId]; // Returns undefined
...
<ErrorBoundary>
    // "Cannot read properties of undefined (reading 'page_name')" won't be processed in ErrorBoundary
    <span>{page.page_name}</span>
</ErrorBoundary>

But if I wrap a problematic place in the component, it works properly.

const page = webtexts[courseId].pages[pageFamilyId]; // Returns undefined
...
const WrapFailingPage: React.FC<{ page: any }> = ({ page }) => {
    return <span>{page.page_name}</span>;
};
...
<ErrorBoundary>
    <WrapFailingPage page={page} /> // The error is properly processed in ErrorBoundary
</ErrorBoundary>

For the demo, I made a simple Codepen - https://codepen.io/OlexanderD/pen/wvpdpxY.

Should the ErrorBoundary behave in that way? Why the inline expressions can be problematic?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你怎么这么可爱啊 2025-01-24 08:25:07

TL;DR

ErrorBoundary 仅跟踪使用 React.createElement(React.Component / React.[V]FC) 创建的代码部分。因此,如果您从自定义 React 组件返回损坏的 JSX,ErrorBoundary 将会拾取它并进行处理。

详细信息:

为随附的 Codepen https://codepen.io/OlexanderD/pen/wvpdpxY

一些术语:

  • element - 任何 HTML 标签。它将被处理为 React.createElement('div', ...)
  • component - 任何 React 组件,而不是原生 HTML 标签。我将被处理为 React.createElement(MyComponent, ...)

根据 文档ErrorBoundary 只能处理其子组件树中的异常,但我尝试从元素捕获异常。

React.createElement() 可以接收 2 种类型的参数:标签name (div, span, ...) 或 React 组件。因此,当我们简单地使用

{fail.absurdIntentionalError}

并将其传递给父 div 时,React 将生成 此代码

React.createElement(
  "div",
  null,
  React.createElement("button", ...),
  showFailingChild &&
  React.createElement("div", null, fail.absurdIntentionalError)
);  

如您所见,我们传递一个元素作为部分的props.children 用于父 div。因此,ErrorBoundary 不会将其作为组件树的一部分进行处理

但是如果我们使用像 FailingComponent 这样的包装器,生成的 JSX 将看起来像这样

React.createElement(
  "div",
  null,
  React.createElement("button", ...),
  showFailingComponent &&
  React.createElement(FailingComponent, null)
);  

现在我们将组件传递给父divprops.childrenErrorBoundary 会将 FailingComponent 的结果处理为组件的一部分。

TL;DR

ErrorBoundary tracks only the code parts that were created with React.createElement(React.Component / React.[V]FC). Therefore, if you return a broken JSX from a custom React component, ErrorBoundary will pick it up and process.

Details:

Examples are made for the attached Codepen https://codepen.io/OlexanderD/pen/wvpdpxY

A bit of terminology:

  • element - any HTML tag. It'll be processed as React.createElement('div', ...)
  • component - any React component, not native HTML tag. I'll be processed as React.createElement(MyComponent, ...)

According to the docs, ErrorBoundary can process exceptions only in their child component tree, but I tried to catch an exception from the element.

React.createElement() can receives 2 types of arguments: tag name (div, span, ...) or React component. Therefore, when we simply use <div>{fail.absurdIntentionalError}</div> and pass it to parent div the React will generate this code:

React.createElement(
  "div",
  null,
  React.createElement("button", ...),
  showFailingChild &&
  React.createElement("div", null, fail.absurdIntentionalError)
);  

As you can see we're passing an element as the part of the props.children for the parent div. Therefore the ErrorBoundary won't process it as the part of the component tree.

But if we use some wrapper like FailingComponent, the generated JSX will look like this:

React.createElement(
  "div",
  null,
  React.createElement("button", ...),
  showFailingComponent &&
  React.createElement(FailingComponent, null)
);  

Now we're passing the component to the props.children for the parent div. And the ErrorBoundary will process the result of the FailingComponent as the part of the component tree.

℡Ms空城旧梦 2025-01-24 08:25:07

当您未正确启动Bugsnag时,有时会发生这种情况。

这是触发错误的示例

    import Bugsnag from '@bugsnag/js';

    const bugsnagClient = Bugsnag.start({
    apiKey: 'my-bugsnag-api-key',
    // plugins: [new BugsnagPluginReact()], <----- assume not there
   releaseStage: 'production',
   });

    const ErrorBoundary = 
    Bugsnag.getPlugin('react').createErrorBoundary(React)

    <ErrorBoundary FallbackComponent={ErrorView}>
    <App store={store} />
    </ErrorBoundary>

以上将触发“ React ErrorBoundary catchary”无法读取未定义的“错误”属性。
因此,在这种情况下,包括该代码将解决以下问题:

    import Bugsnag from '@bugsnag/js';
    import BugsnagPluginReact from '@bugsnag/plugin-react'; // <----- inserted here

    const bugsnagClient = Bugsnag.start({
    apiKey: 'my-bugsnag-api-key',
    plugins: [new BugsnagPluginReact()], // <----- inserted here
   releaseStage: 'production',
   });

It happens sometimes when you have not initiated Bugsnag correctly.

Here is an example that triggers an error:

    import Bugsnag from '@bugsnag/js';

    const bugsnagClient = Bugsnag.start({
    apiKey: 'my-bugsnag-api-key',
    // plugins: [new BugsnagPluginReact()], <----- assume not there
   releaseStage: 'production',
   });

    const ErrorBoundary = 
    Bugsnag.getPlugin('react').createErrorBoundary(React)

    <ErrorBoundary FallbackComponent={ErrorView}>
    <App store={store} />
    </ErrorBoundary>

The above will trigger the "React ErrorBoundary doesn't catch "cannot read properties of undefined" error.
Therefore, in this case including that code will fix the issue as below:

    import Bugsnag from '@bugsnag/js';
    import BugsnagPluginReact from '@bugsnag/plugin-react'; // <----- inserted here

    const bugsnagClient = Bugsnag.start({
    apiKey: 'my-bugsnag-api-key',
    plugins: [new BugsnagPluginReact()], // <----- inserted here
   releaseStage: 'production',
   });
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文