Nacho Elias
Nacho Elias2y ago

useQueryClient is not working as expected

So before v10 I was simply using useQueryClient and had my queryClient strongly typed. Now I moved to v10 and for some reason, the documentation says that the queryClient was removed from the context so I should use the useQueryClient hook directly from @tanstack but if I do so then the queryClient returned by that hook is not the queryClient trpc is using, it's just empty. I made it work by using the trpc.useContext hook coming from my client utils but I definitely think that the docs are a bit f*cked up.
40 Replies
Nacho Elias
Nacho Elias2y ago
Code that used to work
import { useQueryClient } from "react-query";
import { trpc } from "@/utils";

...

export const DeleteExperience = ({ experience }) => {

const queryClient = useQueryClient();

const { mutate: deleteExperience, isLoading } = trpc.useMutation(["deleteExperience"], {
onSuccess: deletedExperience => {
queryClient.setQueryData(
"getExperiences",
prevExperiences => prevExperiences?.filter(e => e.id !== deletedExperience.id) || []
)
}
});
import { useQueryClient } from "react-query";
import { trpc } from "@/utils";

...

export const DeleteExperience = ({ experience }) => {

const queryClient = useQueryClient();

const { mutate: deleteExperience, isLoading } = trpc.useMutation(["deleteExperience"], {
onSuccess: deletedExperience => {
queryClient.setQueryData(
"getExperiences",
prevExperiences => prevExperiences?.filter(e => e.id !== deletedExperience.id) || []
)
}
});
How I made it work in v10
import { trpc } from "@/utils";

export const DeleteExperience = ({ experience}) => {

const trpcContext = trpc.useContext();

const { mutate: deleteExperience, isLoading } = trpc.experience.deleteExperience.useMutation({
onSuccess: deletedExperience => {
trpcContext.experience.getExperiences.setData(
prevExperiences => prevExperiences?.filter(u => u.id !== deletedExperience.id) || []
);
}
});
import { trpc } from "@/utils";

export const DeleteExperience = ({ experience}) => {

const trpcContext = trpc.useContext();

const { mutate: deleteExperience, isLoading } = trpc.experience.deleteExperience.useMutation({
onSuccess: deletedExperience => {
trpcContext.experience.getExperiences.setData(
prevExperiences => prevExperiences?.filter(u => u.id !== deletedExperience.id) || []
);
}
});
So I'm in v10 but the docs explicitly say that in v10 the queryClient was removed from the context and that we should use useQueryClient coming directly from the tanstack dependency
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
julius
julius2y ago
On my phone but to me that all looks correct, you’re supposed to use the proxy utils methods. If anything your usecase from v9 was ”incorrect”. The raw queryclient shouldnt be needed very often 🤔 Im also not sure why you’re setting the data on success instead of just invalidating the cache but thats a different issue
Nacho Elias
Nacho Elias2y ago
Well, it depends on the use case. If my app would be used by multiple users at the same time with the same source of truth, then yes, I need to be up to date with the server data. But if my data is only mutable by the current user, then there's no need to refetch the data if my API returns the mutated entity. In any case, that's another issue. The app works, and yes, it makes way more sense to use the trpc context instead of the queryClient. I'm just surprised that the migration guide explicitly says otherwise. It's a bit confusing
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Nacho Elias
Nacho Elias2y ago
Perfect then, thank u very much. Freakin love this library
julius
julius2y ago
Not sure I follow. We dont recommend using the raw queryclient do we? We just state in there that it has been removed so that people who were using the raw client from the trpc client knows they have to change it
Nacho Elias
Nacho Elias2y ago
So by this I understand that there's no access to the queryClient through the context anymore and that we should start using the queryClient directly from @tanstack/react-query
julius
julius2y ago
then maybe we should rephrase it what it means is
// v9
const ctx = trpc.useContext();
const qc = ctx.queryClient;

// v10
import { useQueryClient } from "@tanstack/react-query";
const qc = useQueryClient();
// v9
const ctx = trpc.useContext();
const qc = ctx.queryClient;

// v10
import { useQueryClient } from "@tanstack/react-query";
const qc = useQueryClient();
the other methods are still there, just moved to the proxy
// v9
const ctx = trpc.useContext();
ctx.invalidateQuery("post.list");

// v10
const utils = trpc.useContext();
utils.post.list.invalidate();
// v9
const ctx = trpc.useContext();
ctx.invalidateQuery("post.list");

// v10
const utils = trpc.useContext();
utils.post.list.invalidate();
but this is (supposed) to point to the queryClient alone fyi, the raw queryclient has always been un-typesafe
qc.invalidateQueries(["post."])
// ^| no autocompletion here
qc.invalidateQueries(["post."])
// ^| no autocompletion here
Nacho Elias
Nacho Elias2y ago
Yup, u're right, that's why to me using useContext is WAY better I mean, I could use the queryClient for other non-server-related data, but I'd say its quite a bad practice. Now, having said that, the queryClient coming from useQueryClient will always be empty, so why would I use it?
julius
julius2y ago
there are things the trpc proxy methods doesn't support yet see here https://github.com/trpc/trpc/issues/3012
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
julius
julius2y ago
i think Jon is working on that issue to implement more features on it
Nacho Elias
Nacho Elias2y ago
yes, but the queryClient coming from useQueryClient is a separate client, is not connected at all to trpc's...
julius
julius2y ago
yes it is, it's all coming from the same context-provider useQueryClient is pulling the qc from context, and your app is wrapped with a react-query context provider if you're using next (withTRPC), we defined it for you: https://github.com/trpc/trpc/blob/e94acb19c440be7aedfde4b24207ea3f5657a986/packages/next/src/withTRPC.tsx#L132 you're not creating a new client when you do useQueryClient
Nacho Elias
Nacho Elias2y ago
if that's true, this should be true (let's assume the data is a primitive value for now)
const dataA = useContext().data.getData()
const dataB = useQueryClient().getQueryData(['data'])

dataA === dataB => this should be true but is false
const dataA = useContext().data.getData()
const dataB = useQueryClient().getQueryData(['data'])

dataA === dataB => this should be true but is false
julius
julius2y ago
Nacho Elias
Nacho Elias2y ago
(let's assume the data is a primitive value for now)
julius
julius2y ago
oh sorry
Nacho Elias
Nacho Elias2y ago
no problem
julius
julius2y ago
gimme 2min i'll make a repro
Nacho Elias
Nacho Elias2y ago
yup
julius
julius2y ago
Nacho Elias
Nacho Elias2y ago
hmmm I defintely was not awaiting for the changes, maybe that's where I went wrong
julius
julius2y ago
i just did to make sure
Nacho Elias
Nacho Elias2y ago
I'll try real quick thanks for the quick response in any case
julius
julius2y ago
works without too
julius
julius2y ago
Nacho Elias
Nacho Elias2y ago
hmmm I wonder where I f*cked it up then hahaha
julius
julius2y ago
make sure you double check the querykey the path should be its own array
Nacho Elias
Nacho Elias2y ago
I'll try real quick and be back
julius
julius2y ago
so like post.list => qc.getQueryData([["post", "list"]]) and if you'd have any input that would go after the path-array qc.getQueryData([["post", "byId"], { id: 1 }]) hence why its much easier to use the proxy 😉 post.list.getData() done
Nacho Elias
Nacho Elias2y ago
Done, found my error, it was the nested array
const dataA = qc.getQueryData(["user", "getUsers"]); => doesn't work
const dataB = qc.getQueryData([["user", "getUsers"]]); => works
const dataA = qc.getQueryData(["user", "getUsers"]); => doesn't work
const dataB = qc.getQueryData([["user", "getUsers"]]); => works
Thank u so much, in any case I still will continue to use trpc's context for type safety
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Nacho Elias
Nacho Elias2y ago
btw, I tried using the dev tools u have mentioned in your docs but they don't work very well. Are there any plans to have RQ dev tools for trpc? Or maybe even using the exact same ones as RQ does? If I'd known that the data was being persisted in that queryClient I think I might have caught the problem sooner
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Nacho Elias
Nacho Elias2y ago
found the issue => (if you're using tRPC v10, install the @next version) nice sorry for the questions I feel dumb as hell anyway, thanks again 🫶
Unknown User
Unknown User2y ago
Message Not Public
Sign In & Join Server To View
Nacho Elias
Nacho Elias2y ago
already made it work and is more than enough thank u!