-
Notifications
You must be signed in to change notification settings - Fork 8k
Document conditional use call order on the server
#8670
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1537,3 +1537,37 @@ const albums = use(fetchData('/albums')); | |
| ``` | ||
|
|
||
| See [caching Promises for Client Components](#caching-promises-for-client-components) for more details. | ||
|
|
||
| --- | ||
|
|
||
| ### `use` returns the value of a different Promise {/*wrong-promise-value*/} | ||
|
|
||
| On the server, React matches each `use` call to its Promise by call order, not by the Promise itself. If a component suspends and runs again, React reuses the Promise already recorded at each position. | ||
|
|
||
| If `use` is called conditionally, and the condition stops `use` from being called once its Promise resolves, the next `use` call takes the skipped position and receives the earlier Promise's value: | ||
|
|
||
| ```js | ||
| function Album() { | ||
| // 🔴 Called on the first attempt, which resolves `tracksPromise` | ||
| // and sets `cache.tracks`. Skipped on the attempt after that. | ||
| const tracks = cache.tracks ?? use(tracksPromise); | ||
|
|
||
| // Now the 1st `use` call instead of the 2nd, so React returns | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Finding these comments a little confusing |
||
| // the Promise recorded in that position: `tracksPromise`. | ||
| const artist = use(artistPromise); | ||
| } | ||
| ``` | ||
|
|
||
| To fix this, move the `use` calls out of the conditions so the same `use` calls run in the same order on every attempt: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This kinda makes it sound like the condition is the issue, which we have already documented is okay... is this relevant? https://react.dev/reference/react/use#conditional-use |
||
|
|
||
| ```js | ||
| function Album() { | ||
| // ✅ Always the 1st and 2nd `use` calls | ||
| const loadedTracks = use(tracksPromise); | ||
| const artist = use(artistPromise); | ||
|
|
||
| const tracks = cache.tracks ?? loadedTracks; | ||
| } | ||
| ``` | ||
|
|
||
| This does not affect the browser. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This cache implementation could be aligned with how the cache is implemented in the code sandboxes above!