PatternAPIUXState
Optimistic Updates Pattern
A pattern for implementing optimistic UI updates that instantly reflect changes while syncing with the server in the background.
Preview
Code
import { useState, useCallback } from 'react'
interface OptimisticState<T> {
data: T
pending: boolean
error: Error | null
}
export function useOptimistic<T>(
initialData: T,
updateFn: (data: T) => Promise<T>
): {
state: OptimisticState<T>
update: (optimisticData: T) => Promise<void>
reset: () => void
} {
const [state, setState] = useState<OptimisticState<T>>({
data: initialData,
pending: false,
error: null,
})
const [previousData, setPreviousData] = useState<T>(initialData)
const update = useCallback(
async (optimisticData: T) => {
// Store previous data for rollback
setPreviousData(state.data)
// Optimistically update UI
setState({
data: optimisticData,
pending: true,
error: null,
})
try {
// Sync with server
const serverData = await updateFn(optimisticData)
setState({
data: serverData,
pending: false,
error: null,
})
} catch (error) {
// Rollback on error
setState({
data: previousData,
pending: false,
error: error instanceof Error ? error : new Error('Update failed'),
})
}
},
[state.data, previousData, updateFn]
)
const reset = useCallback(() => {
setState({
data: initialData,
pending: false,
error: null,
})
}, [initialData])
return { state, update, reset }
}
// Usage example:
function LikeButton({ postId, initialLikes }: { postId: string; initialLikes: number }) {
const { state, update } = useOptimistic(
{ likes: initialLikes, liked: false },
async (data) => {
const res = await fetch(`/api/posts/${postId}/like`, {
method: data.liked ? 'POST' : 'DELETE',
})
return res.json()
}
)
const handleClick = () => {
update({
likes: state.data.liked ? state.data.likes - 1 : state.data.likes + 1,
liked: !state.data.liked,
})
}
return (
<button onClick={handleClick} disabled={state.pending}>
{state.data.liked ? '❤️' : '🤍'} {state.data.likes}
{state.error && <span className="text-red-500">Failed to update</span>}
</button>
)
}Looking for more?
Browse the full collection of patterns or check out other exploration topics.