curi
curi copied to clipboard
(WIP) Suspense
This is a work in progress to determine the API that should be used with React suspense
Prepping Curi to be ready for React Suspense. With Suspense, a navigation cannot be completed until after it has rendered.
When a router is created with the suspend: true
option, the emitted navigation
object will have a finish()
function attached to it. The actual navigation (updating of the history) will not happen until that function is called.
const router = curi(history, routes, {
suspend: true
});
router.respond(({ navigation }) => {
// typeof navigation.finish === "function"
})
There are two changes that need to be done in React.
- Add the
suspend
boolean prop to the<CuriProvider>
. Whensuspend
istrue
, the provider will use deferred updates (not yet implemented because the API doesn't exist!) to update the state with the newresponse
/navigation
.
<CuriProvider router={router} suspend={true}>
{({ response }) => {
const { body:Body } = response;
return <Body />;
}}
</CuriProvider>
- Render a
<FinishNavigation>
inside of a<React.Placeholder>
. The<FinishNavigation>
component will callnavigation.finish()
for you once it mounts (or updates). By placing it inside of a<React.Placeholder>
, we ensure that thecomponentDidMount()
/componentDidUpdate()
triggers are not called until any suspense code has loaded.
The placeholder's fallback component also needs to be wrapped in a <FinishNavigation>
because when the fallback is displayed, the app is essentially rendering a spinner for the next page.
import { FinishNavigation } from "@curi/react";
const User = ({ response }) => (
<React.Placeholder
fallback={
<FinishNavigation>
<Spinner />
</FinishNavigation>
}
>
<FinishNavigation>
<UserContent id={response.params.id} />
</FinishNavigation>
</React.Placeholder>
);
The API here is a little verbose, but a component that combines <React.Placeholder>
and <FinishNavigation>
should help.
import React from "react";
import { FinishNavigation } from "@curi/react";
const NavigationPlaceholder = ({ children, delayMs, fallback }) => (
<React.Placeholder
delayMs={delayMs}
fallback={<FinishNavigation>{fallback}</FinishNavigation>}
>
<FinishNavigation>
{children}
</FinishNavigation>
</React.Placeholder>
);
const User = ({ response }) => (
<NavigationPlaceholder delayMs={2000} fallback={<Spinner />}>
<UserContent id={response.params.id} />
</NavigationPlaceholder>
);
any idea if you could publish this as a separate alpha?
@mfolnovic I'm getting close to releasing v2, at which point I can get this rebased (or at this point it might actually be easier to just copy things into a new PR) and push out a build.
I haven't been paying much attention to React's Suspense development; are they getting closer to releasing suspense for data or is it still only lazy loading?
@pshrmn cool, tnx for info - this PR is closest to real support for Suspense (data fetching) in router from what I tried (and I tried react router, reach router, navi). :)
I haven't been paying much attention to React's Suspense development; are they getting closer to releasing suspense for data or is it still only lazy loading?
As far as I know, they aren't any news regarding suspense for data fetching. It's still planned for ~mid 2019 [1].
[1] https://reactjs.org/blog/2018/11/27/react-16-roadmap.html