Replies: 1 comment
-
Oh, it seems to be pretty easy after all. Here's the full code for "AddItem" component: import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Item, itemsData } from './data';
export function AddItem() {
const [name, setName] = useState('');
const navigate = useNavigate();
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (newItem: Item) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() >= 0.5) {
itemsData.push(newItem);
resolve(newItem);
} else {
reject('Fail!');
}
}, 500);
});
},
onMutate: async (newItem) => {
// Cancel any outgoing refetches
// (so they don't overwrite our optimistic update)
await queryClient.cancelQueries({ queryKey: ['items'] });
// Snapshot the previous value
const previousItems = queryClient.getQueryData(['items']);
// Optimistically update to the new value
queryClient.setQueryData(['items'], (old: Item[]) => [...old, newItem]);
// Return a context object with the snapshotted value
return { previousItems };
},
onError: (err, newItem, context) => {
queryClient.setQueryData(['items'], context.previousItems);
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['items'] });
},
});
const handleAddItem = () => {
mutation.mutate({ name });
navigate('/');
};
return (
<div>
<h2>Add item</h2>
<input
type="text"
onChange={(e) => setName(e.target.value)}
value={name}
/>
<button onClick={handleAddItem}>Add item</button>
</div>
);
} And here's "Home" component: import { QueryClient, useQuery } from '@tanstack/react-query';
import { Outlet, Link, useLoaderData } from 'react-router-dom';
import { Item, itemsData } from './data';
export function Layout() {
return (
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/add-item">Add item</Link>
</li>
</ul>
</nav>
<hr />
<Outlet />
</div>
);
}
export const homeLoader = (queryClient: QueryClient) => async () => {
const query = itemsQuery();
return (
queryClient.getQueryData(query.queryKey) ??
(await queryClient.fetchQuery(query))
);
};
export function Home() {
const initialData = useLoaderData() as Item[];
const { data: items } = useQuery({
...itemsQuery(),
initialData,
});
return (
<div>
<h2>Home</h2>
<ul>
{items.map((item) => (
<li key={item.name}>{item.name}</li>
))}
</ul>
</div>
);
} So in |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Simple use case here, I have two routes/pages:
/home
): Fetches & renders a list of items/add-item
): Page with form where you can add new item using mutationNow when I navigate to "Add item" page, fill out the form and submit it, I make POST request to backend so that new item is added to DB. In this case I don't want to wait for the request to finish before navigating back to home page.
Instead I want to navigate to home page right away and optimistically update the list of rendered items with the form data I submitted. And when the request is finished, I want to again use just the real data from loader. How can I do this? Docs only cover how to do optimistic updates on the same page / on the same "component tree".
Here's a link to example project using react-query + react-router: https://stackblitz.com/edit/github-ljo9w9-fagokw?file=src%2Fmain.tsx
I have followed these two guides in the example project:
What I would like to do is that when I call
handleAddItem
inAddItem
component, I could navigate right away toHome
component and render the data user sent in the mutation function. And theuseQuery
inHome
component would then pull the item data with the optimistically updated item. And when mutation function is done, it calls theinvalidateQueries
normally, causing refetch.For user experience it would be important that I could render the updated list instantly without any delay. I'm not sure how to achieve this with using just react-router (btw, their docs also just cover optimistic updates that are done on the same route) + react-query so help is appreciated 🙏
Beta Was this translation helpful? Give feedback.
All reactions