Fetching and handling content
Learn about the central concepts and hooks for pulling content from your Sanity project into your custom app.
Document handles
- What are Document Handles?
- Why use Document Handles?
- Document Handle structure and components
- Best practices for working with Document Handles
A DocumentHandle
is a core concept in the SDK that enables efficient document operations. A DocumentHandle
is essentially a lightweight reference to a document, containing just enough information to uniquely identify and access it - at minimum, this will include the document’s ID and type, but details about the project and dataset the document belongs to may also be included. This minimalist approach allows the SDK to work with large sets of documents without having to load their full content immediately.
For example, when you use useDocuments()
to fetch a list of movies, instead of loading complete movie documents with all their fields, cast information, and poster images, you get back an array of Document Handles that look like this:
{
documentId: 'movie-123',
documentType: 'movie',
projectId: 'project-123',
dataset: 'production'
}
This lightweight representation serves several important purposes:
- Performance: Loading just the handles instead of full documents reduces initial data transfer and improves application responsiveness
- Flexibility: Handles can be passed to other hooks that load only the specific document data needed for a particular view or operation
- Real-time Updates: The SDK can efficiently track changes to documents by monitoring their handles
Working with Document Handles
Once you have a Document Handle, you can use it with other SDK hooks to access or modify the actual document content. Here are some common patterns:
const movieHandle: DocumentHandle = {
documentId: 'movie_348',
documentType: 'movie'
}
// Get specific fields using useDocumentProjection
const {data} = useDocumentProjection({
...movieHandle,
projection: '{title, releaseYear}'
})
// Get the full document
const {data: movieDoc} = useDocument({...movieHandle})
// Edit a specific field
const editTitle = useEditDocument({
...movieHandle,
path: 'title',
})
This separation between handles and content allows you to build efficient interfaces that load data progressively as needed, while maintaining live synchronization with your Sanity dataset.
Data Retrieval Hooks
useDocuments
- Getting collections of documents
The useDocuments
hook is your primary tool for retrieving collections of documents from your Sanity dataset. It returns Document Handles for documents matching your specified document type (and optional filters and parameters), making it ideal for building document lists and overviews.
const {data, hasMore, isPending, loadMore} = useDocuments({
documentType: 'movie',
batchSize: 10,
orderings: [{ field: '_createdAt', direction: 'desc' }]
})
usePaginatedDocuments
- Paginated document lists
The usePaginatedDocuments
hook provides a more traditional pagination interface compared to the infinite scroll pattern of useDocuments
. This makes it ideal for building interfaces with discrete pages of content and explicit navigation controls:
const {
data,
isPending,
currentPage,
totalPages,
nextPage,
previousPage,
hasNextPage,
hasPreviousPage
} = usePaginatedDocuments({
documentType: 'movie',
pageSize: 10,
orderings: [{ field: '_createdAt', direction: 'desc' }]
})
useDocument
- Reading individual documents
The useDocument
hook provides real-time access to individual document content. It's designed for reading and subscribing to a document's state, incorporating both local and remote changes:
// Get the full document
const {data: movie} = useDocument({...movieHandle})
// Get a specific field
const {data: title} = useDocument({
...movieHandle,
path: 'title',
})
The hook automatically handles displaying local-first, optimistic updates made via the useEditDocument
hook, making it ideal for building collaborative editing interfaces that need to stay synchronized with remote changes. However, for static displays where local-first, optimistic updates aren't needed, consider using useDocumentProjection
(which still return content that's live by default).
useDocumentProjection
- Accessing specific document fields
The useDocumentProjection
hook allows you to efficiently retrieve specific fields from a document using GROQ projections:
const {data: { title, authorName }} = useDocumentProjection({
...documentHandle,
projection: `{
title,
'authorName': author->name
}`
})
Document Manipulation Hooks
useEditDocument
- Modifying documents
This hook is particularly useful for building forms and collaborative editing interfaces. It provides a simple way to update document fields in real-time:
const editTitle = useEditDocument({
...movieHandle,
path: 'title',
})
function handleTitleChange(e: React.ChangeEvent<HTMLInputElement>) {
editTitle(e.currentTarget.value)
}
return (
<input
type="text"
value={title || ''}
onChange={handleTitleChange}
/>
)
useApplyDocumentActions
- Document operations
The useApplyDocumentActions
hook provides a way to perform document operations like publishing, unpublishing, creating, and deleting documents:
import {
useApplyDocumentActions,
publishDocument,
unpublishDocument,
} from '@sanity/sdk-react'
const apply = useApplyDocumentActions()
function MovieActions({ movieHandle }) {
return (
<div>
<button onClick={() => apply(publishDocument(movieHandle))}>
Publish
</button>
<button onClick={() => apply(unpublishDocument(movieHandle))}>
Unpublish
</button>
</div>
)
}
useDocumentEvent
- Handling document events
The useDocumentEvent
hook allows you to subscribe to document events like creation, deletion, and updates. This is useful for building features that need to react to changes in your content:
import {useDocumentEvent, type DocumentEvent} from '@sanity/sdk-react'
const eventCallback = (event) => {
if (event.type === DocumentEvent.DocumentDeletedEvent) {
console.log(`Document ${event.documentId} was deleted`)
} else if (event.type === DocumentEvent.DocumentEditedEvent) {
console.log(`Document ${event.documentId} was edited`)
}
})
useDocumentEvent({
...documentHandle,
onEvent: eventCallback,
})
This hook is particularly valuable when building interfaces that need to maintain consistency with document state changes, such as notification systems or live collaboration features.
Here's an example of using useDocumentEvent
to build a simple notification system that alerts users when documents are modified:
function DocumentChangeNotifier({ documentHandle }) {
const [notifications, setNotifications] = useState<string[]>([])
const eventCallback = (event) => {
switch (event.type) {
case DocumentEvent.DocumentEditedEvent:
setNotifications(prev => [
`Document ${event.documentId} was just edited`,
...prev
])
break
case DocumentEvent.DocumentPublishedEvent:
setNotifications(prev => [
`Document ${event.documentId} was published`,
...prev
])
break
}
}
useDocumentEvent({
...documentHandle,
onEvent: eventCallback,
})
return (
<div className="notifications">
{notifications.map((msg, i) => (
<div key={i} className="notification">{msg}</div>
))}
</div>
)
}
Was this page helpful?