#tRPC inside getServerSideProps
35 messages · Page 1 of 1 (latest)
Indeed i am using a [wildcard] file - the error is the same with or without using params from the router.
did you solved? if not do you any have any reproducible code so we can check and debug
I don’t think it is necessary to use trpc on the server
useQuery is meant to run on the browser
if you really want to trpc requests on the server use createProxySSGHelpers() to get the client
I have already written all my database code in tRPC routers. If tRPC cannot be called from serverside, I would have to rewrite the code elsewhere, again.
Please note that SSG is fine - but the data cannot be used on the backend. So waterfall-loading is impossible afaik,.
Sorry no its not solved, at the moment im keeping ti clientside until i figure out if im even going with trpc for this one.
And its the strangest thing; tRPC is already running on "the same conditions" as the getServerSideProps - its running backend - but I guess all the extra client-cache-etc-etc-wrappings on tRPC, makes it harder to do any direct calls.
I found a solution;
for me, i could do this in getServerSideProps:
const posts = await postsRouter.createCaller({prisma}).posts({ page: 1, pageSize: 7 * 12 } );
that will actually deliver data in getServerSideProps - yes it will stahl the pageload, like any server-side-programming-language has been doing for the last 20+ years - but if thats what you need, its what you need 🙂 also can be used in `/api/à
this is not really only ssg it can be used for ssr
the name is just bad
all useSomething type functions in the react space follow Rules of Hooks and work only in React Components in the browser, getServerSideProps runs in the server, so technically you can just query the db directly, you don't have to send a request to the trpc endpoint
const posts = await prisma.posts.takeMany({take: 7 * 12})
Your solution requires double-implementation of the same findMany - one in getServerSideProps and another in tRPC - my point was to avoid this.
SSG is not a solution for waterfall-dataload.
const getPosts = (args) => prisma.posts.takeMany(args)
trpc.query('posts', args => getPosts)
const getServerSideProps = async () => {
const posts = getPosts()
}
just extract it
there, 1 implementation
As i wrote earlier, the solution is either to write it twice, or have a combined codespace that tRPC and gSSP shares.
Luckily, i found a solution which seems to actually be spot on how tRPC can / should be called (its from their Server Side docs)
const posts = await postsRouter.createCaller({prisma}).posts({ page: 1, pageSize: 7 * 12 } );
if that works then great, sounds like a fine solution
though if you want to have it in the cache as well, you can use the solution outlined above, like seen here:
import { createProxySSGHelpers } from '@trpc/react-query/ssg';
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
import { createContext } from 'server/context';
import { appRouter } from 'server/routers/_app';
import superjson from 'superjson';
import { trpc } from 'utils/trpc';
export async function getServerSideProps(
context: GetServerSidePropsContext<{ id: string }>,
) {
const ssg = createProxySSGHelpers({
router: appRouter,
ctx: await createContext(),
transformer: superjson,
});
const id = context.params?.id as string;
/*
* Prefetching the `post.byId` query here.
* `prefetch` does not return the result and never throws - if you need that behavior, use `fetch` instead.
*/
await ssg.post.byId.prefetch({ id });
// Make sure to return { props: { trpcState: ssg.dehydrate() } }
return {
props: {
trpcState: ssg.dehydrate(),
id,
},
};
}
export default function PostViewPage(
props: InferGetServerSidePropsType<typeof getServerSideProps>,
) {
const { id } = props;
// This query will be immediately available as it's prefetched.
const postQuery = trpc.post.byId.useQuery({ id });
const { data } = postQuery;
return (
<>
<h1>{data.title}</h1>
<em>Created {data.createdAt.toLocaleDateString()}</em>
<p>{data.text}</p>
<h2>Raw data:</h2>
<pre>{JSON.stringify(data, null, 4)}</pre>
</>
);
}
It does indeed - it deliver the exact interface which the client side would have been exposed to; giving the option to have the call either on clientside or serverside.
That solution doesn't work if you have waterfall data-loading, like "load user, if the user is admin, load functions, if not, load posts".
Because you do not get the data, inside getServerSideProps - and therefore you cannot make decisions based on it.
if you have access to the session ofc you can
I cant see how that would be relevant to the problem at hand ?
get userId or something from the session, get the user load into cache, if it's an admin also load posts into cache otherwise redirect to somewhere
Think the process through.
- load the user from the database with trpc. Its a prefetch. You wont know it on one call to getServerSideProps
- next load to a page, you now know the user, THEN you can react to the userId, in another getServerSideProps.
And yes, you can take this example, and then wrap it into something where you say "but then you cache it at the login".
Then take any other example - where you need waterfall data loading - where the data you deliver, depends on the data you first fetch - on the same page call - and it wont work with SSG.
are you trying to static generate or prevent waterfall? These are different goals
If I'm statically generating the page, then yeah, I won't know who requested the page. But then I also don't (shouldn't) have ifs and elses since it's a static page. If it's server side props, which I render per request, ofc I will know who it is if they are logged in
you have a session you can look into
I am not trying to prevent waterfalls. I am exemplifying the problem with SSG if a dev needs to download data as a waterfall.
Again you are taking the example, and not looking at what it represents.