-
-
Notifications
You must be signed in to change notification settings - Fork 10.7k
Feat: Add deferred support #9002
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
Changes from 13 commits
f592b7e
2b9f073
b226c18
5659ff5
a65f06e
44b9632
73269c4
b201ec7
3a9d812
88ad127
ee97229
896dbd3
a596abe
0bd125b
c482f7d
7504d99
e090d66
11ad3c1
7f38497
0dfa170
d059832
d19efea
2b3dbb9
6d38996
3b17591
38236df
3d3498f
ba480dc
d6711e7
4fde4c5
ba6d260
2327800
57e1fe7
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 |
---|---|---|
@@ -0,0 +1,68 @@ | ||
--- | ||
"react-router": patch | ||
"@remix-run/router": patch | ||
--- | ||
|
||
Feat: adds `deferred` support to data routers | ||
|
||
Returning a `deferred` from a `loader` allows you to separate _critical_ loader data that you want to wait for prior to rendering the destination page from _non-critical_ data that you are OK to show a spinner for until it loads. | ||
|
||
```jsx | ||
// In your route loader, return a deferred() and choose per-key whether to | ||
// await the promise or not. As soon as the awaited promises resolve, the | ||
// page will be rendered. | ||
function loader() { | ||
return deferred({ | ||
critical: await getCriticalData(), | ||
lazy1: getLazyData(), | ||
}); | ||
}; | ||
|
||
// In your route element, grab the values from useLoaderData and render them | ||
// with <Deferred> | ||
function DeferredPage() { | ||
let data = useLoaderData(); | ||
return ( | ||
<> | ||
<p>Critical Data: {data.critical}</p> | ||
<Deferred | ||
data={data.lazy} | ||
fallback={<p>Loading...</p>} | ||
errorBoundary={<RenderDeferredError />}> | ||
<RenderDeferredData /> | ||
</Deferred> | ||
</> | ||
); | ||
} | ||
|
||
// Use separate components to render the data once it resolves, and access it | ||
// via the useDeferred hook | ||
function RenderDeferredData() { | ||
let data = useDeferred(); | ||
return <p>Lazy: {data}</p>; | ||
} | ||
|
||
function RenderDeferredError() { | ||
let data = useDeferred(); | ||
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. should we call this 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. Stale changeset again :/. It's |
||
return (<p>Error! {data.message} {data.stack}</p>; | ||
} | ||
``` | ||
|
||
If you want to skip the separate components, you can use the Render Props | ||
pattern and handle the rendering inline: | ||
|
||
```jsx | ||
function DeferredPage() { | ||
let data = useLoaderData(); | ||
return ( | ||
<> | ||
<p>Critical Data: {data.critical}</p> | ||
<Deferred data={data.lazy} fallback={<p>Loading...</p>}> | ||
{({ data }) => | ||
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. There's nothing else for us to pass in here, so let's not put it on a named key and then force them to rename or double-destructure it: // 😕
<Deferred>
{({ data: whatever }) => ()}
</Deferred>
// 😕
<Deferred>
{({ data: { stuff } }) => ()}
</Deferred> Instead just pass the value into the child function: <Deferred>
{value => ()}
</Deferred> 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. oops - that's a stale changeset 😬 We do just pass the resolved data now, will get that updated |
||
isDeferredError(data) ? <p>Error! {data.message}</p> : <p>{data}</p> | ||
} | ||
</Deferred> | ||
</> | ||
); | ||
} | ||
``` |
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.
value={data.lazy}
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.
🙌