-
Notifications
You must be signed in to change notification settings - Fork 20
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
Support React Server Components in preview/live mode #827
Comments
This is unfortunately a known limitation of RSC as of its current design. The live preview lives in the browser and achieves low latency previews by using
Once React v19 comes out we'll be able to give you suspense boundaries with |
Yeah, I thought it was a pretty fundamental issue. What about offering a slightly-higher-latency option that, instead of initiating a client side listener + renderer, just revalidates some backend query leading to a rerendering of a server component (e.g. |
We are indeed working on offering a higher latency option.
So far it looks like The above tests uses |
Hmm strange, I'm looking into the tag-based experiment because that is how I would expect it to work (and also know it to work from experience). So maybe there's something going wrong there. Not sure what you mean with "the RSC's that are affected" though. Looking at the code, I think the
will automatically trigger a refetch for any
which for example could be this visual-editing/apps/next-server-only/src/app/(blog)/[slug]/page.tsx Lines 56 to 60 in 8507f7b
which yes would rerender that component, but that's fine IMO. Is this not working properly, or is this what you mean with "What happens instead is that the entire tree is re-rendered"?
I don't know, maybe there is some more internal caching of responses going on then. I just did a test in my app, I've added an action that revalidates my export async function revalidateTranslations() {
revalidateTag('translations')
} And when I call that from the client: <button onClick={() => revalidateTranslations()}>Revalidate</button> What happens is:
It's really seamless and quite fast as well, with React handling all the complexity involved. So it still feels to me like it would be a great match for this functionality. In the below screen recording you can see it in action: Screen.Recording.2024-02-20.at.21.30.54.mov |
If you look at the RSC stream that sends the updated RSC render tree you'll see it sends the full tree every time. Whether you use a granular That doesn't mean it's going to stay this way, it feels like it's just an opportunity Vercel has to optimize in the future. In any case we have an API you can use your test and find which strategy works best for your case. npm install --save-exact next-sanity@canary @sanity/presentation@latest @sanity/visual-editing@latest The new API lets you put a server action to the new history prop: // app/layout.tsx
import { draftMode } from "next/headers"
import { VisualEditing } from "next-sanity"
export default function RootLayout(props) {
return (
<html>
<body>
{props.children}
{draftMode().isEnabled && (
<VisualEditing refresh={async payload => {
'use server'
// use the payload to call revalidatePath or revalidateTag as you like
}} />
)}
</body>
</html>
)
} If you give it a try please do share your experience with it and how it performs 😄 |
Thanks, I'll give it a shot. Do you have tips for visualizing the RSC stream? The Chrome Network tab just shows an error for those fetches. |
@rijk any update? We are facing the same issue. |
@stipsan Has the official recommendation here changed at all? I think this might be part of what is causing my editor experience to be pretty sluggish. Trying to make sure my implementation is following best practices, but pretty hard to tell what those are at the moment. |
The official recommendation is to use the simple setup when on RSC, for example like this official template: https://github.com/vercel/next.js/tree/canary/examples/cms-sanity
It’s possible to eliminate the latency introduced by these round trips, and we do maintain an official RSC example that implements it, by using These are the two options we recommend, there are others but they rely on hacks and undocumented behavior. |
React Server Components with component level data fetching would be a great match for Portable Text modules with additional data requirements. For example:
module.products
that calls the Storefront API to fetch translations and additional product metadatamodule.reviews
that takes in a Product ID and fetches reviews or its review score from an external sourceBy nature, it's impossible to know what data is needed beforehand to render a block of portable text. That's why the component level data fetching would work great, with RSC preventing client-server waterfalls.
The problem
Visual Editing requires
The way you would implement it is to do a switch like this:
Where the
<Preview>
component is just a client component that wraps the same<Content>
and re-loads the data when it changes:Looks pretty innocent, right? However, because
<Preview>
is a client component, that means everything in<Content>
will be rendered on the client as well. This makes it impossible to use any server components inside your portable text.Current workaround
The only way currently to get the data in for a block of dynamic portable text, is to make sure it's first all synced into Sanity (which is very laborious, involving webhooks, custom sync handlers etc), and then manually expanding all those references in your query (also tedious and leading to other issues).
Sidenote: I found this PR but I couldn't figure out what it does.
The text was updated successfully, but these errors were encountered: