react: Triggering suspense with rejected promise causes re-render instead of error boundary
Do you want to request a feature or report a bug?
This might be a bug. @gaearon and @sebmarkbage shared differing opinions on it in this twitter thread
What is the current behavior?
If you throw a promise that rejects from a react component’s render function, that rejection will be completely ignored. It will not show up in browser console, nor will it trigger a React error boundary. Instead, it will trigger a re-render (the same as if the promise had resolved).
What is the expected behavior?
My expectation was that the error boundary would be hit and the component would not re-render. Sebastian’s tweet indicates that that is not the desired behavior, though.
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
This impacts react@experimental
, and also react@>=16.9.0
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 19 (10 by maintainers)
Suspense has a very specific and strict contract. It’s not currently documented, which is why we’re asking not to build integrations with it except as an experiment. The examples above do not satisfy that contract.
Here’s this contract in a nutshell. A Suspense-compatible cache should follow these rules:
The bolded part explains that you’re supposed to cache the errors, too. We’ll document this contract when Suspense for data fetching is considered stable.
The mechanism just needs a callback really. We kind of abused the Promise object for this purpose but it causes more confusion as a result. That’s why we’ll likely just switch to a different API for this.
The wrapper could definitely accept a promise and rejecting it would cause it to trigger an error boundary.
The point of the implementation details is that React may not store anything about where the promise was used. Including the error boundary. So depending on the details (such as if parent props have changed in the meantime) we may need to reexecute the renders to figure out which error boundary to trigger and what to render instead.
So semantically the real error comes from the function throwing an error after being reexecuted. This should be synchronous and not after one tick which is what would happen with a Promise.
Anyway you should probably file a new issue so we don’t spam this one.