-
Notifications
You must be signed in to change notification settings - Fork 46.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bugfix: Nested useOpaqueIdentifier references (#22553)
* Handle render phase updates explicitly We fire a warning in development if a component is updated during the render phase (with the exception of local hook updates, which have their own defined behavior). Because it's not a supported React pattern, we don't have that many tests that trigger this path. But it is meant to have reasonable semantics when it does happen, so that if it accidentally ships to production, the app doesn't crash unnecessarily. The behavior is not super well-defined, though. There are also some _internal_ React implementation details that intentionally to rely on this behavior. Most prominently, selective hydration and useOpaqueIdentifier. I need to tweak the behavior of render phase updates slightly as part of a fix for useOpaqueIdentifier. This shouldn't cause a user-facing change in behavior outside of useOpaqueIdentifier, but it does require that we explicitly model render phase updates. * Bugfix: Nested useOpaqueIdentifier calls Fixes an issue where multiple useOpaqueIdentifier hooks are upgraded to client ids within the same render. The way the upgrade works is that useOpaqueIdentifier schedules a render phase update then throws an error to trigger React's error recovery mechanism. The normal error recovery mechanism is designed for errors that occur as a result of interleaved mutations, so we usually only retry a single time, synchronously, before giving up. useOpaqueIdentifier is different because the error its throws when upgrading is not caused by an interleaved mutation. Rather, it happens when an ID is referenced for the first time inside a client-rendered tree (i.e. sommething that wasn't part of the initial server render). The fact that it relies on the error recovery mechanism is an implementation detail. And a single recovery attempt may be insufficient. For example, if a parent and a child component may reference different ids, and both are mounted as a result of the same client update, that will trigger two separate error recovery attempts. Because render phase updates are not allowed when triggered from userspace — we log a warning in developement to prevent them — we can assume that if something does update during the render phase, it is one of our "legit" implementation details like useOpaqueIdentifier. So we can keep retrying until we succeed — up to a limit, to protect against inifite loops. I chose 50 since that's the limit we use for commit phase updates.
- Loading branch information
Showing
4 changed files
with
314 additions
and
166 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Oops, something went wrong.