Skip to content

Instantly share code, notes, and snippets.

@trinhvanminh
Created September 10, 2025 07:37
Show Gist options
  • Select an option

  • Save trinhvanminh/5f07d0ef715e87b658b8106eea218801 to your computer and use it in GitHub Desktop.

Select an option

Save trinhvanminh/5f07d0ef715e87b658b8106eea218801 to your computer and use it in GitHub Desktop.
import React from 'react';
import ReactDOM from 'react-dom/client';
import {
QueryClient,
QueryClientProvider,
useMutation,
useQuery,
} from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
const queryClient = new QueryClient();
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<ReactQueryDevtools />
<Example />
</QueryClientProvider>
);
}
const wait = async (ms: number = 300) => {
return await new Promise((resolve) => {
setTimeout(() => {
resolve();
}, ms);
});
};
function Example() {
const { isPending, error, data, isFetching, isFetched } = useQuery({
queryKey: ['todos'],
queryFn: async () => {
const res = await fetch(
'https://68c106ca0b196b9ce1c5a7b3.mockapi.io/api/todos'
);
if (!res.ok) throw new Error('Network response was not ok');
return res.json();
},
});
const addTodoMutation = useMutation({
mutationFn: async (newTodo: string) => {
if (newTodo.startsWith('error')) {
throw new Error('Failed to add todo');
}
const res = await fetch(
'https://68c106ca0b196b9ce1c5a7b3.mockapi.io/api/todos',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: newTodo,
}),
}
);
if (!res.ok) throw new Error('Failed to add todo');
return res.json();
},
onSettled: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
});
if (isPending) return 'Loading...';
if (error) return 'An error has occurred: ' + error.message;
return (
<div>
<button
onClick={() =>
addTodoMutation.mutate(`test ${new Date().toISOString()}`)
}
>
Add todo
</button>
<button
onClick={() =>
addTodoMutation.mutate(`error ${new Date().toISOString()}`)
}
>
Add error todo
</button>
<ul>
{data.map((todo) => (
<li key={todo.id}>{todo.text.slice(0, 40)}</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.replace('error', 'no-error')
)
}
>
Retry
</button>
</li>
)}
</ul>
<div>{isFetching ? 'Updating...' : ''}</div>
</div>
);
}
const rootElement = document.getElementById('root') as HTMLElement;
ReactDOM.createRoot(rootElement).render(<App />);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment