Troubleshooting live previews in Next.js project with dynamic loading and React errors.
I feel your pain! The good news is you don't need that generic wrapper component at all. The modern approach with Sanity's Live Content API is much cleaner and avoids the code duplication issue entirely.
The React error you're seeing ("A previously unvisited boundary must have exactly one root segment") is likely caused by the dynamic loading creating unstable component boundaries. This is a known React issue that can happen when components are dynamically loaded in certain ways, especially with Suspense boundaries.
Here's the recommended approach using Sanity's Live Content API with defineLive:
1. Set up defineLive once (in something like sanity/lib/live.ts):
import { defineLive } from "next-sanity/live"
import { client } from "./client"
export const { sanityFetch, SanityLive } = defineLive({
client,
serverToken: process.env.SANITY_API_READ_TOKEN,
browserToken: process.env.NEXT_PUBLIC_SANITY_API_READ_TOKEN,
})2. Use the same component everywhere - just swap client.fetch for sanityFetch:
// app/blog/[slug]/page.tsx
import { sanityFetch } from "@/sanity/lib/live"
import { BlogPost } from "@/components/BlogPost"
export default async function BlogPostPage({ params }) {
const { slug } = await params
const { data: post } = await sanityFetch({
query: `*[_type == "post" && slug.current == $slug][0]`,
params: { slug }
})
return <BlogPost post={post} />
}3. Add the <SanityLive /> component once in your root layout:
// app/layout.tsx
import { SanityLive } from "@/sanity/lib/live"
import { draftMode } from "next/headers"
export default async function RootLayout({ children }) {
return (
<html>
<body>
{children}
{(await draftMode()).isEnabled && <SanityLive />}
</body>
</html>
)
}That's it! No component duplication, no dynamic loading, no weird wrapper logic. The same BlogPost component works for both live preview and production. When draft mode is enabled, <SanityLive /> automatically makes all sanityFetch calls reactive to content changes.
The Live Content API handles the real-time updates without websockets or complex cache invalidation. Your components stay simple, and you avoid those gnarly React boundary errors entirely.
If you're on an older version of next-sanity (pre-v11), note that the import path changed from next-sanity to next-sanity/live - check the changelog if you run into import issues.
Sanity – Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.