【问题标题】:Why do React components that throw errors render twice?为什么抛出错误的 React 组件会渲染两次?
【发布时间】:2020-01-03 03:37:08
【问题描述】:

我一直在尝试使用 react-cache 样式的组件,并在 render 方法中直接调用 Web 服务,向 React.Suspense 组件抛出一个 Promise,并在数据存在时重新渲染。他们调用 Web 服务,检查响应,然后根据响应呈现或抛出错误,直至错误边界。我注意到,每当在组件中引发错误时,它都会呈现两次。第一次调用堆栈看起来正常,第二次调用堆栈包含对invokeGuardedCallbackDev和invokeGuardedCallback的调用,这似乎与React有关,确保即使在开发构建中被错误边界“捕获”时,错误也会出现在控制台中.

我可以使用 react 和 react-dom 16.8.6 重现这一点,只需渲染一个像这样的组件:https://codesandbox.io/s/components-that-throw-render-twice-i26qc

我想知道为什么会发生这种情况,因为它会导致组件从 Web 服务重新获取数据,重新抛出另一个 Promise,并导致控制台中出现“Uncaught Promise”错误。

【问题讨论】:

  • 不错的收获!对于它的价值,这可能不是由于 react-error-overlay (如代码框描述中所述)。我能够使用普通的旧 CDN 链接重现此内容,但只能使用开发版而不是缩小版。这可能是 GitHub 上问题的一个很好的候选者。此外,在App 中添加错误边界对重新渲染没有帮助;它仍然发生。并且不会在 16.2.0 中发生,但会在 16.3.0 中发生!

标签: reactjs


【解决方案1】:

这似乎是由 react/react-dom 的最近更改引起的。如果您将两者都恢复到版本16.0.0,您将看到它只呈现组件一次。见:https://codesandbox.io/s/components-that-throw-render-twice-03fdb

查看version history,似乎修复了一些与 React 中的错误处理相关的错误,因此重新渲染似乎是针对其中一个错误的解决方法的结果。

但是,这对您的应用程序来说应该不是问题,因为在 React 应用程序中渲染函数应该是纯的(没有副作用)。所以基本上,React 可以随时调用你的渲染函数。

要解决这个问题,您应该避免依赖组件不重新渲染,而是使用效果挂钩或类似功能仅在某些道具/状态更改时获取。

来源:https://github.com/facebook/react/issues/16130#issuecomment-521637592

【讨论】:

    【解决方案2】:

    我认为错误边界实际上并没有捕捉到抛出的错误。

    来自https://reactjs.org/docs/error-boundaries.html

    注意

    错误边界不会捕获以下错误:

    异步代码(例如 setTimeout 或 requestAnimationFrame 回调)

    异步代码在这种情况下包含Promises

    另见https://reactjs.org/docs/error-boundaries.html#how-about-event-handlers

    错误边界不会在事件处理程序中捕获错误。

    如果您需要在事件处理程序中捕获错误,请使用常规 JavaScript try / catch 语句。

    【讨论】:

    • 你知道为什么组件会渲染两次吗? (代码框链接中的示例)
    猜你喜欢
    • 2017-11-22
    • 2020-09-07
    • 2020-11-22
    • 2023-01-24
    • 1970-01-01
    • 2021-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多