我一直在尝试一些组件,这些组件可以在render方法中执行react-cache风格的事情并进行Web服务调用,将承诺扔给React.Suspense组件,并在有数据时重新呈现。他们调用Web服务,检查响应,然后根据响应呈现错误或将错误抛出到错误边界。我注意到,每当在组件中引发错误时,它都会呈现两次。第一次调用栈看起来正常,第二次调用栈包含对invokeGuardedCallbackDev和invokeGuardedCallback的调用,这似乎与React有关,即使在开发构建中被错误边界“捕获”时,React也可以确保错误出现在控制台中
我可以通过只渲染一个像这样的组件https://codesandbox.io/s/components-that-throw-render-twice-i26qc来用react and react-dom 16.8.6复制它。
我想知道为什么会这样,因为这导致组件从Web服务重新获取数据,重新抛出另一个诺言,并导致控制台中出现“ Uncaught Promise”错误。
答案 0 :(得分:2)
我认为错误边界实际上并没有捕获引发的错误。
来自https://reactjs.org/docs/error-boundaries.html:
在这种情况下,注意
错误边界不能捕获以下错误:
异步代码(例如setTimeout或requestAnimationFrame回调)
异步代码包括 Promise 。
另请参见https://reactjs.org/docs/error-boundaries.html#how-about-event-handlers:
错误边界不会捕获事件处理程序内部的错误。
如果您需要在事件处理程序中捕获错误,请使用常规的JavaScript try / catch语句。
答案 1 :(得分:2)
这似乎是由于最近的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