canastro
canastro2w ago

`useSuspenseQuery` returns unexpected `.json` and `.metadata` (SuperJSON)

I'm following the docs here: https://trpc.io/docs/client/tanstack-react-query/server-components I have this query client builder:
export const makeQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: {
// With SSR, we usually want to set some default staleTime
// above 0 to avoid refetching immediately on the client
staleTime: 30 * 1000,
},
dehydrate: {
serializeData: SuperJSON.serialize,
shouldDehydrateQuery: (query) =>
defaultShouldDehydrateQuery(query) || query.state.status === 'pending',
},
hydrate: {
deserializeData: SuperJSON.deserialize,
},
},
});
export const makeQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: {
// With SSR, we usually want to set some default staleTime
// above 0 to avoid refetching immediately on the client
staleTime: 30 * 1000,
},
dehydrate: {
serializeData: SuperJSON.serialize,
shouldDehydrateQuery: (query) =>
defaultShouldDehydrateQuery(query) || query.state.status === 'pending',
},
hydrate: {
deserializeData: SuperJSON.deserialize,
},
},
});
I have this prefetch:
const getQueryClient = React.cache(makeQueryClient);
export const createTRPC = async (slug?: string) => {
const headersList = await headers();
const ctx = await createContext(headersList, slug);

return createTRPCOptionsProxy({
ctx,
router: appRouter,
queryClient: getQueryClient(),
});
};

...

function async MyComponent() {
const trpc = await createTRPC(slug);
void prefetch(trpc.story.listByPublication.queryOptions());
}
const getQueryClient = React.cache(makeQueryClient);
export const createTRPC = async (slug?: string) => {
const headersList = await headers();
const ctx = await createContext(headersList, slug);

return createTRPCOptionsProxy({
ctx,
router: appRouter,
queryClient: getQueryClient(),
});
};

...

function async MyComponent() {
const trpc = await createTRPC(slug);
void prefetch(trpc.story.listByPublication.queryOptions());
}
And when, on my client component, I use a suspense query:
'use client';

export default function MyClientComponent(props: { slug: string }) {
const trpc = useTRPC();
const { data } = useSuspenseQuery(trpc.story.listByPublication.queryOptions());
'use client';

export default function MyClientComponent(props: { slug: string }) {
const trpc = useTRPC();
const { data } = useSuspenseQuery(trpc.story.listByPublication.queryOptions());
I receive an object with .json and .metadata which seem to be be stuff from superJSON, but that are not properly typed. I haven't seen this in previous versions... it looked like the values were properly deserialized before being returned, but now I seem to receive the raw superjson value.... am I missing something?
1 Reply
canastro
canastroOP2w ago
This is my TRPCProvider:
function TRPCReactProvider(props: { children: ReactNode }) {
const params = useParams<{ slug?: string }>();
const queryClient = getQueryClient();
const slug = params.slug ?? currentSlug;

const [trpcClient] = useState(() =>
createTRPCClient<AppRouter>({
links: [
loggerLink({
enabled: (op) =>
process.env.NODE_ENV === "development" ||
(op.direction === "down" && op.result instanceof Error),
}),
httpBatchStreamLink({
transformer: SuperJSON,
headers: () => {
if (!slug) return {};
return { "x-publication-slug": slug };
},
url: `${getBaseUrl()}/api/trpc`,
}),
],
})
);

return (
<QueryClientProvider client={queryClient}>
<TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
<ReactQueryDevtools initialIsOpen={false} />
{props.children}
</TRPCProvider>
</QueryClientProvider>
);
}
function TRPCReactProvider(props: { children: ReactNode }) {
const params = useParams<{ slug?: string }>();
const queryClient = getQueryClient();
const slug = params.slug ?? currentSlug;

const [trpcClient] = useState(() =>
createTRPCClient<AppRouter>({
links: [
loggerLink({
enabled: (op) =>
process.env.NODE_ENV === "development" ||
(op.direction === "down" && op.result instanceof Error),
}),
httpBatchStreamLink({
transformer: SuperJSON,
headers: () => {
if (!slug) return {};
return { "x-publication-slug": slug };
},
url: `${getBaseUrl()}/api/trpc`,
}),
],
})
);

return (
<QueryClientProvider client={queryClient}>
<TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
<ReactQueryDevtools initialIsOpen={false} />
{props.children}
</TRPCProvider>
</QueryClientProvider>
);
}
I'm using pnpm and node v22 Some relevant packages:
"@tanstack/react-query": "^5.74.4",
"@tanstack/react-query-devtools": "^5.74.4",
"@trpc/client": "^11.1.0",
"@trpc/server": "^11.1.0",
"@trpc/tanstack-react-query": "^11.1.0",
"next": "15.2.2",
"@tanstack/react-query": "^5.74.4",
"@tanstack/react-query-devtools": "^5.74.4",
"@trpc/client": "^11.1.0",
"@trpc/server": "^11.1.0",
"@trpc/tanstack-react-query": "^11.1.0",
"next": "15.2.2",

Did you find this page helpful?