usePreviewSubscription returns null data on last call in catch-all route

21 replies
Last updated: Apr 29, 2021
I’m using a catch-all route
[[…slug]].tsx
, and inside that page I have :

  const test = usePreviewSubscription(routeQuery, {
    params: { slug },
    initialData: data,
    enabled: preview && slug,
  });
If I log out
test
, in preview mode, it’s called 4 times.. but the last time
test.data
is null… anyone experienced the same thing?
AI Update

This is a common issue with usePreviewSubscription and is typically related to React Strict Mode in development. Here's what's happening:

In development mode, React Strict Mode intentionally double-invokes component renders and effects to help detect side effects. This is why you're seeing multiple calls (4 instead of 2). The null data on the last call is usually part of this lifecycle behavior where the subscription is being torn down and re-established.

Common causes and solutions:

  1. React Strict Mode behavior - This is expected in development. The null value typically appears during the unmount/remount cycle. In production builds (where Strict Mode doesn't double-invoke), you'll likely see this behavior disappear.

  2. Slug parameter timing - With catch-all routes like [[...slug]].tsx, the slug parameter might be undefined initially during hydration, causing the subscription to fire with invalid params. Make sure you're handling this:

const test = usePreviewSubscription(routeQuery, {
  params: { slug: slug || '' }, // or slug?.join('/') for array slugs
  initialData: data,
  enabled: preview && !!slug, // double-bang ensures truthy check
});
  1. Guard against null data - Always handle the null case defensively:
const displayData = test.data ?? data; // fallback to initialData

Modern alternative: If you're starting fresh or can migrate, consider using the Live Content API with defineLive instead of usePreviewSubscription. It's the current recommended approach for real-time preview in Next.js and handles these edge cases more gracefully:

import { defineLive } from 'next-sanity/live'

export const { sanityFetch, SanityLive } = defineLive({
  client,
  browserToken: token,
  serverToken: token,
})

The Live Content API is more robust and doesn't have the same subscription lifecycle issues you're experiencing with the older usePreviewSubscription hook. It also works seamlessly with Draft Mode for preview functionality.

Bottom line: The behavior you're seeing is likely normal in development with Strict Mode. Just ensure you're handling null data gracefully with a fallback to your initialData, and it should work fine in production.

Show original thread
21 replies
There are some known instances where specific whitespaces in your query will cause the query to return nothing, when otherwise it would return something.
If you comment out the entire hook, does
data
have data in it?
Yes, then I have data coming from
getStaticProps
I’ve seen other people mentioning white space in query, but as far as I can see there are no whitespace in the query
Was looking for examples but yeah it’s most often in resolving references I think like
[] ->
needs to be
[]->
And using
select()
can return empty but usually just where you’ve used it.
And your Sanity client has an API token right, so it can read draft documents?
Yes, I think everything is in order otherwise.
I tried to simplify my query now, and it actually works..
Hm, allright.. then I atleast know somewhat where the issue is
Thanks for helping out 🙂
GL!
Thanks!
I'm experiencing the same as you
user R
. Were you able to fix it?
It’ll be a syntax issue in your query. It works server side but not in the preview client. Most common cause is additional trailing comma’s.

*[] {
  one: "one",
  two: "two", <-- this comma is a problem
}
It’ll be a syntax issue in your query. It works server side but not in the preview client. Most common cause is additional trailing comma’s.

*[] {
  one: "one",
  two: "two", <-- this comma is a problem
}
thanks Simeon, will check it out!
If you’re using
select()
my current understanding is that one won’t work at all in the preview client.
Strip out parts of your query line-by-line until the data loads as you expect – and you’ll find the offending line.
ah, turns out it was my own fault... was querying for a specific slug, but didn't pass it onto the component, so it worked server side but not client side
😄 easy done!
but thanks for the help, really appreciate your quick responses
haha yeah 😛

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.

Was this answer helpful?