useOptimistic
Instantly update UI with mutation results created directly in an application while awaiting updated content from Content Lake.
The useOptimistic hook lets you opt in to instant updates for specific content. It renders the anticipated result of a mutation right away, instead of waiting for the updated document to come back from Content Lake. Import it from @sanity/visual-editing/react. It is not React's built-in useOptimistic.
For the full signature and type parameters, see useOptimistic in the generated reference. This page covers what the generated reference doesn't express: the reducer contract and the shape of the action a reducer receives.
The Svelte hook exported from @sanity/visual-editing/svelte has a different shape: it takes initial and returns {value, update}, where value is a readable store. The generated reference doesn't cover the Svelte entry point.
It's primarily used for enabling drag-and-drop functionality for Visual Editing. You can learn more about how to use it in the Drag and drop documentation.
Behavior
When no mutations are pending, the hook returns the passthrough value unchanged. When a mutation is pending, it returns the optimistically updated state your reducers produce.
Outside the Presentation Tool, useOptimistic is a no-op and always returns the passthrough value. Optimistic state applies only when your application renders in Presentation's preview iframe or window and the connected Studio supports optimistic updates.
Reducers
Reducers(state, action):
A reducer receives the current state and an action and returns the next state. Signature:
(state: T, action: OptimisticReducerAction<U>) => T. Returnstateunchanged to ignore an action. When an array of reducers is supplied, they run in order, each receiving the previous reducer's return value.Parameters
state
T
The current state, equal to the passthrough value when no reducers have been applied.
action
OptimisticReducerAction<U>
The action received by the reducer, used to optimistically update the state.
This reducer replaces a list of products with the version carried on the mutated category document, and ignores actions for any other document:
'use client'
import type {SanityDocument} from '@sanity/client'
import {useOptimistic} from '@sanity/visual-editing/react'
type Product = {_id: string; title: string}
export function ProductList(props: {categoryId: string; products: Product[]}) {
const products = useOptimistic<Product[], SanityDocument<{products?: Product[]}>>(
props.products,
(state, action) => {
if (action.type !== 'mutate' || action.id !== props.categoryId) {
return state
}
return action.document.products ?? state
},
)
return (
<ul>
{products.map((product) => (
<li key={product._id}>{product.title}</li>
))}
</ul>
)
}Reducer actions
Every reducer receives an action object with the following properties:
Requireddocument
U
The document that was updated.
Requiredid
string
The published ID of the mutated document, with any
drafts.prefix removed. Compare this against a published document ID, not againstaction.document._id.RequiredoriginalId
string
The ID of the document that was mutated, including any
drafts.prefix. Matchesaction.document._id.Requiredtype
'appear' | 'mutate' | 'disappear'
The type of action occurring (only
mutateis currently supported).