Discussion on fetching fresh data from API in custom document view component using useClient() and a reference implementation of useListeningQuery hook.
The issue you're experiencing is related to how useClient() is configured in your Studio component. By default, the client may be using the CDN or a specific perspective that doesn't immediately reflect the latest changes.
Based on the official Studio React Hooks documentation, here's how to properly configure useClient() to fetch fresh data:
const client = useClient({ apiVersion: '2023-01-01' }).withConfig({ perspective: 'raw' })Why this matters:
- Perspective: Setting
perspective: 'raw'ensures you're querying both published and draft documents, which is typically what you want in Studio when viewing the latest changes - CDN caching: When you use
useClient()without additional configuration, it may be hitting cached data. The.withConfig()method allows you to override settings
Better approach using useDocumentStore():
Instead of polling with delays, you should use Studio's built-in document listening capabilities. The useDocumentStore() hook provides real-time updates:
import { useMemo } from 'react'
import { useDocumentStore } from 'sanity'
import { useObservable } from 'react-rx'
const INITIAL_STATE = []
const fetchConcepts = () => {
const docId = document.displayed._id
const documentStore = useDocumentStore()
const observable = useMemo(() =>
documentStore.listenQuery(
trunkBuilder(),
{ id: docId },
{}
)
, [documentStore, docId])
const results = useObservable(observable, INITIAL_STATE)
// results will automatically update when the document changes
useEffect(() => {
if (results?._updatedAt === document.displayed._updatedAt) {
if (results.topConcepts === null && results.orphans.length < 1) {
setNoConcept(true)
} else {
setNoConcept(false)
setConcepts(results)
}
setIsLoading(false)
}
}, [results])
}Why your recursive approach wasn't working:
Even with delays, you were likely hitting cached responses. The CDN doesn't invalidate on every request—it serves cached content until the cache updates. Your recursive calls were just fetching the same cached data repeatedly, which is why the _updatedAt values never changed.
The listenQuery() method from useDocumentStore() eliminates this problem entirely by establishing a real-time listener that's aware of document mutations as they happen in Studio. This is the recommended pattern for custom document views that need to stay in sync with document changes.
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.