Skip to content

React Example: Optimistic Updates Ui

Source URL: https://tanstack.com/query/latest/docs/framework/react/examples/optimistic-updates-ui

TanStack

Query v5v5

AlphaTry TanStack CLI

Search…

K

Auto

Log In

StartRC

StartRC

Router

Router

Query

Query

Table

Table

DBbeta

DBbeta

AIalpha

AIalpha

Formnew

Formnew

Virtual

Virtual

Pacerbeta

Pacerbeta

Hotkeysalpha

Hotkeysalpha

Storealpha

Storealpha

Devtoolsalpha

Devtoolsalpha

CLIalpha

CLIalpha

More Libraries

More Libraries

BuilderAlpha

BuilderAlpha

FeedBeta

FeedBeta

Maintainers

Maintainers

Partners

Partners

Showcase

Showcase

Blog

Blog

LearnNEW

LearnNEW

Support

Support

Stats

Stats

Discord

Discord

Merch

Merch

GitHub

GitHub

Ethos

Ethos

Tenets

Tenets

Brand Guide

Brand Guide

Docs

Partners

CodeRabbitCodeRabbitCloudflareCloudflareAG GridAG GridSerpAPISerpAPINetlifyNetlifyNeonNeonWorkOSWorkOSClerkClerkConvexConvexElectricElectricPowerSyncPowerSyncSentrySentryRailwayRailwayPrismaPrismaStrapiStrapiUnkeyUnkeyCodeRabbitCodeRabbitCloudflareCloudflareAG GridAG GridSerpAPISerpAPINetlifyNetlifyNeonNeonWorkOSWorkOSClerkClerkConvexConvexElectricElectricPowerSyncPowerSyncSentrySentryRailwayRailwayPrismaPrismaStrapiStrapiUnkeyUnkey

ReactReact

Latest

Search…

K

latest

ReactReact

Latest

Github StackBlitz CodeSandbox

Code ExplorerCode

Interactive SandboxSandbox

  • src

    • pages

      • api

      • index.tsx file iconindex.tsx

  • .gitignore file icon.gitignore

  • README.md file iconREADME.md

  • next.config.js file iconnext.config.js

  • package.json file iconpackage.json

  • tsconfig.json file icontsconfig.json

tsx

import * as React from 'react'
import {
QueryClient,
QueryClientProvider,
useMutation,
useQuery,
useQueryClient,
} from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
const client = new QueryClient()
type Todos = {
items: ReadonlyArray<{
id: string
text: string
}>
ts: number
}
async function fetchTodos(): Promise<Todos> {
const response = await fetch('/api/data')
return await response.json()
}
function useTodos() {
return useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
}
function Example() {
const queryClient = useQueryClient()
const [text, setText] = React.useState('')
const todoQuery = useTodos()
const addTodoMutation = useMutation({
mutationFn: async (newTodo: string) => {
const response = await fetch('/api/data', {
method: 'POST',
body: JSON.stringify({ text: newTodo }),
headers: { 'Content-Type': 'application/json' },
})
if (!response.ok) {
throw new Error('Something went wrong.')
}
return await response.json()
},
onSettled: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
})
return (
<p>
In this example, new items can be created using a mutation. The new item
will be optimistically added to the list in hopes that the server
accepts the item. If it does, the list is refetched with the true items
from the list. Every now and then, the mutation may fail though. When
that happens, the previous list of items is restored and the list is
again refetched from the server.
</p>
<form
onSubmit={(e) => {
e.preventDefault()
setText('')
addTodoMutation.mutate(text)
}}
>
<input
type="text"
onChange={(event) => setText(event.target.value)}
value={text}
/>
<button disabled={addTodoMutation.isPending}>Create</button>
</form>
{todoQuery.isSuccess && (
<>
{/* The type of queryInfo.data will be narrowed because we check for isSuccess first */}
Updated At: {new Date(todoQuery.data.ts).toLocaleTimeString()}
<ul>
{todoQuery.data.items.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
{addTodoMutation.isPending && (
<li style={{ opacity: 0.5 }}>{addTodoMutation.variables}</li>
)}
{addTodoMutation.isError && (
<li style={{ color: 'red' }}>
{addTodoMutation.variables}
<button
onClick={() =>
addTodoMutation.mutate(addTodoMutation.variables)
}
>
Retry
</button>
</li>
)}
</ul>
{todoQuery.isFetching && <div>Updating in background...</div>}
</>
)}
{todoQuery.isPending && 'Loading'}
{todoQuery.error instanceof Error && todoQuery.error.message}
)
}
export default function App() {
return (
)
}

CodeRabbitCodeRabbitCloudflareCloudflareAG GridAG GridSerpAPISerpAPINetlifyNetlifyNeonNeonWorkOSWorkOSClerkClerkConvexConvexElectricElectricPowerSyncPowerSyncSentrySentryRailwayRailwayPrismaPrismaStrapiStrapiUnkeyUnkey

“If you’re serious about really understanding React Query, there’s no better way than with query.gg”—Tanner Linsley

Learn More](https://query.gg?s=tanstack)