[pull] main from react:main - #624
Merged
Merged
Conversation
## Summary
Adds a new API to `react-dom` called `browser()`.
`browser()` returns a "usable" that will error during SSR and resolve
during rendering in the browser. The purpose is to allow you to express
the idea that a component should suspend on the server but not in the
browser. The method is not available inside a `react-server`
environment. This is a client only feature.
This is a `react-dom` API because the concept of browser doesn't apply
generally to React itself.
This codifies a pattern that is common in some apps where you error
during SSR to prevent rendering some component on the server and you end
up suppressing the error that is reported in the client to avoid this
appearing like a problem rather than intended behavior. Unfortunately
this is not an option for many because hacking around to prevent errors
from being logged is not practical for many
By making this a React API we enabled this common pattern in any React
using library or application
```tsx
import {use, Suspense} from 'react';
import {browser} from 'react-dom';
function BrowserOnly() {
use(browser());
return <ClientContent />;
}
function App() {
return (
<Suspense fallback={<Fallback />}>
<BrowserOnly />
</Suspense>
);
}
```
It is an error to `use(browser())` outside of a Suspense boundary
because you cannot recover from the root. this restriction may be lifted
in the future but is part of the current limitations of the API
## Implementation
Deferring rendering to a downstream system is modeled in React already
as recoverable errors. The idea is that in some environments you might
not want to report something directly as an error because a later
environment has an opportunity to recover from it without alerting the
user to the mishap. This concept also shows up in RSC with halted
references. They can "recover" in a later render by eventually resolving
to some value.
To model the idea of "render in the browser" we are really just modeling
an intentional recoverable error. However since you don't want to treat
this kind of error as exceptional we intentionally suppress logging.
Additionally since aborting a server render is semantically equivalent
to "erroring" in every unfinished task we also support aborting with a
`browser()` so you can describe ending a stream with intentional holes
that won't be logged as errors in the browser when hydrating.
One interesting thing we do with this particular API is it returns an
object that is isomorphic and it's the `use` or `abort` function that
handles differing behaviors. This means you can create these objects in
module scope and use them even in complex scenarios like server
rendering inside the browser while React is rendering.
This implementation is flagged so we can disable the feature quickly if
we decide to not ship this in a stable. It is going into React
unprefixed for now because the semantics are clear and the utility is
widely known.
## Alternatives
We considered `useBrowser()` or a similar hook however this means you
must call it unconditionally. There are use cases where props might
influence whether you want to allow something to render during SSR or
not. for instance you might have a data fetching library that accepts
initial data on the server but if it doesn't receive initial data it
falls back to browser only rendering.
Another consideration is a throwing function like just calling
`browser()` would throw if called during an SSR render. The main reason
we do not think this is a good idea is because you can then call this
arbitrarily deep and the throw can be caught and might be suppressed
accidentally. By making it a usable it can only be done in hooks or
hook-like contexts.
I've been triaging some lifecycle races during sessions with BFCache involved and noticed a few type errors in real world scenario. These objects were not properly typed, fixing in this PR.
The main reason why I am doing this is because there is no API in the browser to "unmount" the created panel. If you have React DevTools installed, we should always create a panel, but the contents of the panel should be dynamically populated based on the target. If it is not a React app, we will continue showing the stub message. Previously, we wouldn't mount a panel at all, and historically we've received a few reports of this as a bug.
I have noticed inconsistency errors being thrown during browser navigations that involve entries from BFCache. The main argument on why this could be affecting React DevTools backend lifecycle is the fact that Chrome kills the port manually, while freezing and preserving the JavaScript heap - https://developer.chrome.com/blog/bfcache-extension-messaging-changes. Basically, we could end up in a permutation, where port is dead, but Backend / Agent are alive. Such setup is not expected by React DevTools. On `main`: https://github.com/user-attachments/assets/9ca10286-b545-4384-bd6b-33d9a4ddde3d With these changes: https://github.com/user-attachments/assets/c4639c4a-6385-4248-a5c4-a39895d7fff6 I couldn't come up with a good test for this yet, but I will try to add something. I am not convinced yet that emulating `pagehide` / `pageshow` would be sufficient to reproduce browser environment during BFCache entries.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )