T
TanStack•3y ago
rising-crimson

How to reflect mutation post in the actual (fetch) data?

Hi, I started today using react-query, and I am pretty impressed with the results I've achieved so far. However I am with a problem: I have the following useQuery:
const {data: categories, isLoading: isCategoriesLoading, setData: setCategoriesData} = useQuery(
['categories'],
fetchCategories
);
const {data: categories, isLoading: isCategoriesLoading, setData: setCategoriesData} = useQuery(
['categories'],
fetchCategories
);
When I post a new category, i would like to append the category object to categories, I am trying to do this following this article in the docs: https://tanstack.com/query/v4/docs/react/guides/mutations#persist-mutations
const postCategoriesMutation = useMutation({
mutationFn: ({category: category}) => postCategory(category),
onSuccess: (result, variables, context) => {
queryClient.setQueryData(['categories'], (cats) =>{
console.log(cats); // prints undefined
return [...cats, result] // me trying to set the 'categories' data
})
},
});
const postCategoriesMutation = useMutation({
mutationFn: ({category: category}) => postCategory(category),
onSuccess: (result, variables, context) => {
queryClient.setQueryData(['categories'], (cats) =>{
console.log(cats); // prints undefined
return [...cats, result] // me trying to set the 'categories' data
})
},
});
So like in the comment, when I try to do something similar to what's in the docs, I get undefined. I also have the const queryClient = new QueryClient()inside const MyComponent = () => {// here}, but I also call it in the App.js which is where <QueryClientProvider> is. I don't know if this is problematic and if it adds to the problem, but maybe I shouldn't instantiate queryClient twice? Ultimately I would like to append the added category to categories.
10 Replies
foreign-sapphire
foreign-sapphire•3y ago
Hi, yes you should not create multiple instances of query client, especially inside a component since this means a new instance at each render. You could start by having just one queryClient, the one from App.js passed to QueryClientProvider.
foreign-sapphire
foreign-sapphire•3y ago
Don't know if you are aware of this but if not you should have a look here : https://tkdodo.eu/blog/react-query-fa-qs#2-the-queryclient-is-not-stable
React Query FAQs
Answering the most frequently asked React Query questions
foreign-sapphire
foreign-sapphire•3y ago
The whole blog is a must-read
rising-crimson
rising-crimsonOP•3y ago
Hi, that makes sense. The article seems to be really helpful, i'll have a look thanks!
foreign-sapphire
foreign-sapphire•3y ago
"those articles" 😉
rising-crimson
rising-crimsonOP•3y ago
Indeed, thanks for sharing My App.js looks like this
export const App = () => {
const element = useRoutes(AppRoutes);
return (
<QueryClientProvider client={queryClient}>
<Layout>
{element}
</Layout>
</QueryClientProvider>

);
};
export const App = () => {
const element = useRoutes(AppRoutes);
return (
<QueryClientProvider client={queryClient}>
<Layout>
{element}
</Layout>
</QueryClientProvider>

);
};
My Layout.js
export const Layout = (props) => {
const { children } = props;
return (
<div>
<NavMenu/>
<Container className="responsive max" tag="main">
{children}
</Container>
</div>
);
};
export const Layout = (props) => {
const { children } = props;
return (
<div>
<NavMenu/>
<Container className="responsive max" tag="main">
{children}
</Container>
</div>
);
};
AppRoutes.js - I need to have access to the client in these routes:
const AppRoutes = [
///...
{ // i need to grab queryClient here
path: '/recipe/edit/:id',
element: <CreateRecipe/>
},
{ // and here
path: '/create-recipe',
element: <ProtectedComponent Component={CreateRecipe} />
},
const AppRoutes = [
///...
{ // i need to grab queryClient here
path: '/recipe/edit/:id',
element: <CreateRecipe/>
},
{ // and here
path: '/create-recipe',
element: <ProtectedComponent Component={CreateRecipe} />
},

I am not sure how to procede. Maybe something along the lines of const UseQueryClient = ({ children }) => children(useQueryClient()) ? Damn it, Nevermind. It was simply export const queryClient = new QueryClient() 😄 (even though it seems isn't the best solution) tysm
foreign-sapphire
foreign-sapphire•3y ago
In our case we avoid this by having a « init » step where we pass the queryclient and initialise its defaults. Then we retrieve it using either using the useQueryClient hook when in React. Or through our store which has a ref to the queryclient setup at the end of the init.
rising-crimson
rising-crimsonOP•3y ago
right now I don't have any global state or store that i can use, but I am starting to need it (also to possibly share react query client reference through it). Do you recommend any solution? I tried React Context before improving my code but I think it's not really what I am looking for in terms of maintainability and code readability
foreign-sapphire
foreign-sapphire•3y ago
Hi. The QueryClientProvider acts/is a React context. So you could use useQueryClient within React component to retrieve the queryClient. For the JS world, you need a ref to the queryClient passed to QuzryClientProvider, in a store for ex.
foreign-sapphire
foreign-sapphire•3y ago
An example of what we do (simplified example), should you need it => https://codesandbox.io/s/react-query-and-query-defaults-vywtm?
GLabat
CodeSandbox
react-query and query defaults - CodeSandbox
Use query defaults to help factorisation of queryFn in addition to be able to access queryClient and perform query call inside queryFn

Did you find this page helpful?