In this chapter our goal is to create TRPC integration into our project. We are going to do that by starting the basic TRPC setup and then we're gonna go ahead and make sure that we have the proper client-side fetcher, server-side fetcher and we're also gonna explore the new syntax. This is something that I did not do in my original build of this application. And I'm gonna explain what it is in a moment. Just before we do that, as always, ensure that you are on your main master branch, ensure that you have merged all the changes from the previous chapter, and you can do that by doing git status and confirm that you get a similar message.
So now what we are going to do is we're going to head to trpc.io. I would suggest that you follow the documentation in the same way I am simply so you know how to simply so you learn your way around their website, right? So you can start with the quick start if you prefer it this way. This tutorial right here will teach you the most basic app router building tutorial, right? But here's what I'm going to do.
So what I like to do is I like to click on using Next.js, which is here at the top. And in here, usually, if you go ahead and follow this, you're going to notice that this instruction is for pages router. So you can see that this uses source pages underscore app. This is not what we are building with. So if you follow this, you're not going to get the result you need.
Instead, usually what we would do is we would follow this React query integration here with the server components. This is what we would usually do. This is what we did in my previous courses. But if you notice, we now have another option, 10-stack React Query and a little star here. So what's the difference?
As you can see here, Compared to the classic React Query integration, this client is simpler and more 10-stack query native, providing factories for common 10-stack React Query interfaces like query keys, query options, and mutation options. So yes, TRPC actually made an announcement where it introduced the new TANstack React query integration. Previously, you might have been used to having this thing right here built into TRPC. So you would do trpc.greeting.useQuery. You can see that now it has changed.
You are now using useQuery natively as you would without TRPC, right? And then you plug and play TRPC into React Query, or should I say, TanStack React Query. And while on the first site, this might seem more complicated because this is two lines instead of one and it includes a wrapper. I actually fully agree with this decision and I think that this is the way going forward. And they've printed out some key changes here, some reasons for the change here.
So simplicity, familiarity, react, and of course, maintainability. Imagine for them what a challenge it must have been to keep their versioning of TRPC with their own 10 stack query built in. So that had to be extremely difficult for them. So I'm glad that they found a way to make this easier so we can get better updates faster. And of course the TRPC and 10 stack query team, I'm sure are in very close discussion about changes.
So you didn't have to worry about them getting out of sync. So I am excited to try this new integration for the first time. Let's go ahead and do it. So if you have access to this, because I can't guarantee you that the documentation will change, right? But if you have access to this exact thing, go ahead and click on the client usage, make sure you're in 10 stack React query and click on server components, right?
This is what you want to click on. They give you a caution here. If you want to, you can read about advanced server rendering, right? If you want to understand the different types that exist and some foot guns to avoid. But I will try to showcase them through example later on.
So, first thing we need to do is add the RPC to our existing project. As you can see right here, we have to install these packages right here. So what I'm going to do is I'm going to use bun, and I'm just going to copy this. But before I just run this command, I'm going to show you what are the current latest versions of all of these commands. So here are all the versions of each package.
So trpc-server, client, and 10-stack-react-query are all at 11.0.3. That is the current version that I'm using. They are all the same. And I'm pretty sure all trpc packages have to be on the same version. So make sure you check that once you install them in the package.
Jason, the 10 stack react query, the independent package is currently at 572.1. Zod is at 324.2 and client only and server only is at these. So I'm going to add them individually. So bun add at the RPC slash server at 11.0 point three that is the first package we have to add after this I have to add the RPC client like this After that, I'm going to copy this one. 11.0.3 for 10-stack React query.
After that, I have independent 10-stack reaquiry at 572.1. There we go. 572.1. And then we have Zod at 3.24. 3.24.2.
Zod at 3.24, 3.24.2. Client only is at 0.0.1. And server only is at the same version. There we go. So now you can see that I have a lot of changes here.
Let me just pull this graph down a bit and go inside of my package.json. And these are all of my changes. So 10-stack React Query at 5721. The all trpc packages, three of them, client, server, and 10-stack React Query at 11.0.3. Client only at 0.0.1.
Server only at 0.0.1. And Zod, which I already had installed, at 324.2. And I think that this is exactly what we had here. So all TRPC at 11.0.3, 10-Stack at 572.1 and Zod at 324.2. So I'm just showing you this because this package has changed, right?
And I don't want you to have any breaking changes. I want you to be able to follow this tutorial as closely as I am. Alright, so make sure you have those packages and now we can go forward which says create a trpc router. So in here they give us a sample backend. If for whatever reason you don't have this code snippet, It's a very short snippet, you can just pause the screen and copy it, we're now going to add it to trpc slash init dot ds.
So I'm going to go inside of here, I'm going to create the trpc folder and inside I'm going to create init dot ds. There we go. So we are importing initTRPC from TRPC server, cache from React. We have a mock context here. So this is pretending to load some user ID, right.
And in here we just do const T init tRPC dot create right here and in here we export the create tRPC router create color factory and base procedure So make sure you have this init file. So that's our sample backend. Now we have to create a query client factory. So let's go ahead and create query client.es. So inside of trpc folder, query client.es.
And now I'm just going to copy everything here and I'm going to show you how that looks like. So it looks like there is one thing that I don't have defined, superJSON here. So let's go ahead and just install that. Bonad superJSON and my current version of superJSON is 2.2.2. So if you want to use the same version, you can do this.
So make sure you have super JSON. There we go. Right now, I'm going to comment it out simply because I'm not using it yet. I'm going to enable all of that later. So if you don't have the snippet, we do these two imports and we export the function to make query client.
In here, we return the query client from tanstack react query. We add some stale time and we prepare some dehydration and later hydration as well that's it after we have done the query client you can also look at the default settings and what they mean here Now we have to create a TRPC client for client component. So create a client.tsx file. And this is what we are going to use to wrap our app with, right, so it has access to tRPC. So you can copy this entire thing here and paste it.
This one is a little bit longer. And it seems like we have one issue here. So let me just see if I forgot to add that. Yes, my apologies. So if you look in the sample back end, we added the init file.
But inside of my trpcclient.tsx, I'm trying to look for this file, and I don't have it. That's because I forgot that here it is. It's another very simple file. So make sure you have this init file. And in here, just create, actually, let me see the full.
So it's folder routers. And then inside underscore app dot ds. And in here, you can paste this very simple snippet. So we are importing base procedure and create the RPC router from the init file. And then in here, you should now be able to just you know delete it and write it again or command shift and p and restart my apologies reload window and that should reset the import You should now have no errors in your client.tsx so ensure that you have routers underscore app.
So this is like your basic procedure here which just returns some text based on the props it's been sent. Let's go back inside of client.tsx and in here I want to do some change. You can see that we do this kind of confusing if clause. So if we have the Vercel URL, then we return it with a protocol. Otherwise, return localhost 3000.
First of all, I don't know if you're going to deploy this to Vercel, right? So this is a Vercel-specific environment variable. And the second thing is I don't know if your app is running on localhost 3000. So this is what I suggest we do and make this even simpler. Go ahead inside of your .environment file right here.
And you can call this global and add next public app URL and do HTTP localhost 3000 or wherever your app is running on, right? So if you do bun run dev, where does your app run? You can just copy this. For example, be careful of the protocol, right? Don't accidentally put HTTPS if your app is not running on that.
So now that you have next public app URL, what you can do is you can go back inside of the client, inside of the get URL function, and you can simplify this. So you can remove this completely. Just leave the if type of window is undefined. And in here, you can just return process.environment, next public app URL. Always double check that it's the exact same one.
So you can copy it here and paste it here. So in production, when you deploy, you're going to have to remember that you have to change this environment variable to your active domain, so your domain.com with the protocol, but without the forward slash at the end. We are going to do that when we deploy. So this is basically the client.tsx, which is basically the provider for the 10-stack query and the trpc. It's the client-side provider.
Client components need this. This is how we are going to be accessing the hooks. Without this, you would get the errors. And after you've done that, so I quickly came back to this, the sample back, and let me close this now. We've finished this.
And now we're working on the client context. And now once you've done that, you have to mount this in the root of your application. So don't forget that. Let's go ahead inside of our app folder, inside of our app route group, this route layout right here. And inside of here, you basically have to wrap your TRPC provider.
So I'm going to do that here, trpcProvider. Make sure you import trpcProvider like this. It seems to be missing something. Let me just see. TRPC provider, where did it import from TRPC client?
Let me try reloading the window to confirm that this is an error. Okay, I'm going to go ahead and pause and see how to resolve it I think it's because I'm using the incorrect import here so yeah I should have noticed immediately We're definitely not using this. So we should be using, what's the name of this? Let me find it here. I can't find a name.
TRPC React Provider. My apologies. TRPC React Provider. That's the one we need. There we go.
After you do that, no errors. My apologies for missing that. All right, so make sure you have that set. Let's see what our next step is. So this is all set.
And now we need to create a server fetcher, right? So I told you we need, we have the basic router, we did that, we did the client-side fetcher, and now we need the server-side fetcher. So that's what we're doing now. So create server.tsx inside of your trpc folder here. Let me just close everything else here.
So inside of trpc server dot ts and paste everything inside. And now I'm just going to go ahead and see what this is. So if your router is in a separate server, you pass the client. All right. So that's just an example, I believe.
So I think you can remove that. Yeah. Okay. I doubled check with my original source code and I'm pretty confident that this is all we need for the server-side caller. So it's important that you use server only here so that even if you accidentally import this somewhere in the client, your app will break, right?
The build will not work and you will get a bunch of errors, so you don't have to worry about any secrets leaking. That's always something you have to take care of when you do this server and client side mix, which can be something that happens with server components. Great. So I think after server.tsx, that's it. We can now use our API.
There are several ways we can do this. We can do it with prefetching. We can do it with directly calling inside of a client component. Or we can also, let me just scroll down even further down, we can also directly just call data in a server component. So let's try just a couple of these examples.
Basically, our goal is to learn how to fetch categories for the layout.tsx. So how about we learn on that example, and I think that can count as exploring the new syntax then. Okay, so we've set up the TRPC. So let's add the categories router. Let's see how we would do that, right?
So I'm going to go inside of source. And in here, I'm going to create a new folder called modules. And this is where we are later going to organize all of those components, which I was telling you about. Now in here, create categories. And now I'm going to create a server folder here, and procedures.cs.
And now inside of here, you can export const, categories, router, create TRPC router from TRPC init like this. And let's do get many here to be base procedure from trpc init. So you should have all of these things, right? We've added the create trpc router helper and we have the base procedure here. So base procedure dot query and inside of here basically add an asynchronous method.
Just an arrow function like this. And you can do for now, you can just return, you know, hello world for now. We are going to connect real data in a second here. Now that you have this categories router, we're going to go back inside of trpc routers underscore app. And instead of using this Hello, I'm going to remove it completely.
And I'm just going to do categories, categories router from modulus categories server procedures. In here we can remove the base procedure because we no longer need it. I mean the import and the Zod import as well, like this. So now your TRPC should have access to the categories router. We are going to go ahead and try that out in a second.
So how about we go inside of source app, app, home, app, app, home, page.dsx. This is a clean, clean page. So we can try it out here. So we're going to try multiple methods here. Let's do bun run dev.
Or wait, was it running? It was running. My apologies. So make sure you have your app running. And now what I want to try first is just getting the data in a server component, but I want to use maybe this way, right?
So let's try this. We have to import getQueryClient. Let's do that. Const query client will be getQueryClient from trpc server. We have that.
We have to mark this as an asynchronous function. That's important. And then we're just gonna do const categories, and this will be awaitQueryClient.fetchQuery, And then inside, I suppose we have to pass in the trpc.categories.getMany. So trpc from the server, right? Make sure you didn't accidentally get another import because you can import TRPC from client as well.
TRPC and you can see how it recognizes the categories. And it recognizes get many like this. And I have to run this. Or maybe again, I'm exploring this syntax for the first time. So I'm sorry if I'm making mistakes at the moment.
So let me see, maybe get many, and then query options. Okay. No errors now. I think that this might work now. So let me try JSON stringify.
Maybe, I don't know. Let's see. Categories seem to have proper types for me here. And I'm just going to show you a few tips right before we try, before I go further. If you hover over categories, you should have the proper types.
If for whatever reason, you don't have proper types, if you are getting errors, or if you have a type of any, there is a fix for that and that is a common issue. So if you go inside of, Let me try and find maybe extra information. Frequently asked questions. It doesn't work. I'm getting any everywhere.
There are a couple of things you have to do. Ensure that strict is set to true in your tsconfig.json. Let's do that together. Inside of your tsconfig.json, your strict should be set to true. So that is fine.
Then make sure your TRPC versions match. We know that that is okay as well. So again, all of your TRPCs should have the same version. That's another reason why it can fail. This actually happened to me the first time I developed with the RPC.
And the final fix was this, adding this VS Code settings. So you can copy this, and you can create .VSCode slash settings.json. And it's actually recommended that you do, especially if you work in a team. So let me create a new folder, .vs code, and inside settings.json, and then just paste this inside. So this is actually recommended, and you can click allow if this pops up.
I would recommend having this, especially if you work in a team, so that every one of your teammates will have working TRPC. Now let's go back into the app folder, home, inside of page.tsx. Try again. Oh, and now I have, There we go. So it was loading any for a second.
Probably... Yeah, if yours is still loading any, make sure to reload your window, right? So you need to give him some time. There we go. Now I'm 100% certain that this is working.
If I go ahead and refresh, there we go. You can see it says, Hello World right here. That's how we would use this on the server. But what if this is a client component? What then?
Well, first of all, we can't use async, which means we can't use await, which means we can't use the RPC server at all. So now let's go back inside of the client usage, 10-stack React query, server components, scrolling all the way down to using your API. And now inside of here, we are going to skip this first example. This is the most interesting example, actually, but we're going to do that later. Now let's use this one.
Hooks can only be used in client components. So we just import our good old use query from 10 stack react query, and then we import use the RPC from at the RPC client like this use the RPC. And then we define the RPC here instead of the query client. So you can see the equivalence, right? You can already see what this actually is.
And I think I can do this myself, right? So use query like this. And do I need query options? I need query options like this. There we go.
And now, this will, I think, be... You wouldn't actually do this. You would do categories.data, right? Because this is loading at first. This is client-side.
We are not awaiting this. For example, is loading, categories is loading. Like this. So let's see and refresh here now. Is this working or not?
Let me see. 404 not... Oh, yes, I think there is one thing that I forgot to do here. Yes, the reason mine is not working, and yours probably isn't as well, is because I think I forgot one thing here. Maybe it's here in the sample backend.
Yes. So I keep closing this, but there are three things from here that I need. This, we need this. I think after that it's going to work. So we need to create an API folder trpc and then trpc route.ts inside.
So let's go and do that. Inside of the app route group, I'm going to create an API folder. And then inside of here, I'm going to create trpc folder. And then a dynamic route trpc, and then inside route.ts. So basically, the way client-side works is by fetching your backend, your API.
But if you don't give it a way to fetch, if you don't give it what to fetch, it will not be able to do that. So the reason server-side worked is because Server-side has direct access to the database. It doesn't need to use the API. Whereas client-side needs the API. That's how client-side components work, right?
They call the server and the server writes back using an API. Server components don't work in that way. That's why the first example worked. So ensure that you have the same structure, slash API slash DRPC, because that's what we expect here. And I'm pretty confident that now this should work.
And it is great. Is loading is not displaying properly, but the data is. So we are officially managing to get the data. I'm not sure why this is... Oh, I think because it's a Boolean, so I have to probably maybe do it like this.
There we go. So IsLoading false, but you can see how in the beginning it's true. There we go. So we now have examples of how to use tRPC in a client component, and we also did an example of how to do it in a server component. And you learn the crucial difference, ironically, because we forgot to add the TRPC API, right?
But you've learned the crucial difference of how these two methods work. The client side will go over the fetch API, whereas server will directly call the database because that's what server components do. So now what I want to do, we've learned the new syntax. Now I want to refetch the categories in the layout, and I want to client-side fetch the categories in categories sidebar.tsx and I want to get rid of my custom trpc types in exchange for the new inferred types from TRPC router. So what we have to do now is we have to go back to our categories router which we've separated here in the categories module.
So let's go inside of here And let's go inside of the layout in the app home, because this is where we fetch and format the data. So what do we need? We need these two imports first. Don't worry if you're thinking, oh, why wouldn't you just abstract that? We will.
But let me go ahead and demonstrate step by step how one would do that. So we get payload and we get config promise here. Let's go ahead and get that here. There we go. Payload and config promise.
And then let's go ahead and let's fetch our data and sort our categories by name. There we go. And then let's go ahead and format our data. This time we don't even need the custom category because we will be able to infer this, but this can be a category from at payload types like this. And then in here, you would just return the formatted data like this.
So now, when you refresh this, you should be seeing much more data available to you here. But there are a couple of things that we can improve. First thing that comes to mind is this. It will be very annoying that we have to write this in every single procedure. So what we can do is we can go inside of trpc.init right here and we can extend this base procedure.
So let's go ahead and do that. We're going to do trpc procedure dot use asynchronous. The structure next because this is a middleware, right? So we're gonna have to tell it to just continue forward after we do this. And in here, we are going to connect to payload.
Because pretty much every single procedure of ours will have to talk to Payload, right? And let's return next like this. But before we do this, we need the config from Payload config. So just add this. There we go.
Config from payload config. It can be called config promise, config whatever you want because it's a default export. And then you have to add that to your context. And the way I want to do that is by extending the context. And I will just call this database.
If you want to, you can call it payload, you know, whatever you prefer. Database, payload, maybe payload is more correct, right? And then inside of your procedures here, what you can do is you can destructure the context from here. And then you can just do context.payload.find. As simple as that.
And you no longer have to import this in all of your procedures. So this will now work every time you use a base procedure. If you want to, you can create a separate procedure called, I don't know, database procedure, right? If you are certain that you are not going to be using base procedure every time you need database. And also feel free to decide.
Maybe I want this to be database and then I'm going to have to use context.database.find. I actually might even like this more. I think the only reason I am kind of considering not doing it is because it has this. Technically, it could go to database.database, but this isn't really, this is something else, right? This is the database adapter.
So yeah, I just don't want you to be confused when you see that. But yeah, choose how you want to call this a payload instance. I like database, it's short, and we can do things like this. Great, so now what's cool is that while this also works, So if I go, whoops, I have no idea what this is, page DSX right here. So while this works now, you can see that categories now also have their proper types, except probably this part is probably incorrect.
But you can see how this works now. And I am now able to infer this type further. So what I want to do next, we've added the categories router. But what I want to do next is prefetch those categories in layout.tsx. So let's go ahead and do the following.
So pre-fetching will allow us to leverage the speed of server components because you saw that server components have direct access to the database but we are also going to use the client-side use query simply because that's easier to work with. When you have use query, you can invalidate, you can refetch, you can add pagination, you can add infinite load, all of the things that are just unnecessarily difficult to do in server components. So that's why we're going to introduce the best of server components combined with the best of client components. That's why they propose this in using your API. This is the first example they put because it is the best example to use.
Let's go ahead and try it out. So now we're going to go inside of app folder and we're going to go inside of home, inside of layout here. And we are now going to remove this data from here. We don't need it like this. And instead, what we're going to do is we're going to prefetch.
So let's learn how to prefetch following this. We need the query client from trpc server. You can also remove all three of these. So just go ahead and get this, remove custom category from here. So get query client from trpc server.
That's the first thing. And then we need to void queryClientPrefetchQuery and pass in this. So like this, void queryClientPrefetchQuery, PRPC from server, make sure you have it from server, dot categories. And inside of query options, you would usually pass something, but ours has nothing and query options.getMany. So you need to get to the actual procedure like this.
And now This is prefetched, which means that the server component will prefetch this before it goes into the client component. And what we can do now is we no longer have to pass this here. We don't have to pass it like that. Instead, we're going to use the hydration boundary. So hydration boundary comes from...
We need to import these two, so let me just add them here at the top. There we go. So 10 stack react query, dehydrate and hydration boundary. So let's just add hydration boundary around the search filters, because this is where we want to pass our data to. And we have to add the state and dehydrate the query client.
And here's the cool thing. You might be thinking that this is PRPC specific documentation. This is actually React query documentation. So that's why this new way of doing this is in my opinion better, because you can just look at React query documentation and you will understand the TRPC. I think that's a great win-win situation.
So now, what do we do with the search filters? How does search filters access what we've just prefetched? Well, now we use the hook here, right? But instead of having to load it, it's going to be immediately available to us. So instead of search filters here, what we are going to do is the following.
So there are two ways you can do it. You can do it how we previously showcased, how it currently is in page right here. So we can do it like this. But we can also leverage. OK, so this is something, if we want to reuse it, blah, blah, blah.
This. I think we want to leverage suspense now, right? But let me just confirm that I am doing this correctly. You may prefer handling loading and error states. Yes, I would.
But I just want to confirm that this is what I'm doing. Where does this prefetch now come from? Maybe this is what they've created now, prefetch. Yeah, you can see how they've kind of, yeah, maybe we could add those. Might not be a bad idea.
Let's add this as well. Yeah, I think this will help us actually. So if you want to, yeah, you can go inside of source, PRPC, server, and then you could, oh, you have to now turn this into server.tsx. So server.ts becomes server.tsx. You have to import hydration boundary from 10-stack react query and the hydrate from 10 stack react query and now we have the hydrate client shorthand so we can now just do hydrate client like this from TRPC server so you don't have to import it from there.
And you can also export prefetch from here. Let me just see where does this come from. Like this. Accept this any. Will it work with unknown?
Okay I actually don't like the fact that we have to use any, so I would rather not do it that way. I'm okay with explicitly typing things. So I'm just going to revert this to the state it was. And here I'm just going to bring back hydration boundary like this. So hydration boundary and the hydrate from the 10 stack React query.
Okay, we're not going to complicate it. So in here we are prefetching the query, right? So this is the same thing as this. They are just using their helper. This is the same thing.
And now, inside of here, you can do the following. You can wrap suspense here, like this, from react, and a fallback loading, like this. And you can go inside of search filters. And what you can do here is you can add the RPC, use the RPC from the client. And in here, you can get raw data.
So use suspense query from 10 stack React query, trpc categories, get many. And then this data would be the same thing. But this way, you are getting it from here, right? And let me just see. Did I do something incorrectly here?
So useSuspenseQueryTRPC. Where am I getting TRPC from? UseTRPC. So this seems to be an error. So I'm just going to go ahead and research what it is.
So I'm pretty sure this happens here because of our getMany method here. I think it's because of the way we are formatting the data here. So I'm just interested, if I return the data like this, is it still the same? It still acts the same. I just want to confirm that it's not something else here.
So I'm going to go ahead and reload the window. Again, I'm exploring this syntax for the first time. So I think this is a good way to learn, actually, because you see me struggling as well. All right. So it does detect these things, but this is what it has a problem with.
Must have a symbol iterator method that returns an iterator. Because if I simplify this, if I just did this test hello, it still has the same issue. Interesting. How about just hello? All right, so I'm gonna go ahead and explore a bit further.
All right. I think I figured out what's wrong. So first I thought maybe it's something with the tsconfig here, because that's what the Google says, right? But then this came to mind. So bring back your formatted data here.
You can import the category here. And here's how I solve, I think I solve it. Here's how. So I think they have a mistake in this part right here. Because as I said, the cool thing is that useSuspenseQuery is from 10-stack React query, which means that I can just look at 10-stack query documentation.
And I saw that the return is the same object as useQuery. So I thought, oh, okay, how about I destructure it then? And then would you look at that? It's exactly what we would expect to get. Not only that, you can see that the data still matches.
I'm still not getting any errors here. But we do have to mark this as use client now. So search filters should be use client at this point. So mark that as use client and let's see what we are working with. And there we go, you can see how now you have a loading for a second and then it displays everything.
So similarly, it works similarly as the one below, but it loads much, much faster. This isn't really a good example because this is pretty static data, but later you will definitely notice that having this combination, which is, let me show you, this combination of using a prefetch in a server component and then passing through hydration boundary something through here, and then using useSuspendSquery is faster. Another tip, there is a chance some of you might be getting some errors here. And I'm gonna show you what I mean. There is an error reported that some might be receiving the maximum update depth exceeded.
It looks like this, maximum update depth exceeded, right? I want to bring this to your attention because I did experience this. You can see that down here, I left a comment. This is how my error looked like. Maximum update depth exceeded.
And one solution for me was to downgrade React query to 5.66.3. So if your app is filled with those errors, right, for maximum update depth, maybe or may not happen, you can go in here and you can change the version to 5.66.3. That's where the issue does not appear anymore. But since this is a new syntax that we are trying, maybe it was resolved in this new PanStacked query integration. So I'm not going to change anything from now.
And just to bring some ease of your mind, you can continue developing even if you have that maximum update depth error. It's not going to break anything, right? But I just don't want you to be scared that you did something wrong. No, there's a chance that you might get the maximum update depth exceeded. Great.
So now, as you can see, we load our data in a new way. And now you can decide if you are okay with having your data loaded this way, I'm talking about this part. You can see the data is now just transferred here. So categories has the data, right? And we just pass the data to the categories sidebar.
If you want to, you can make categories sidebar independent of the data now, right? So if you want to, you can fetch the data. Let me just show you using your API. You can now fetch the data like this. You can get the TRPC here.
And then in here, you can get the data using use query from 10 stack to react query, make sure to import use the RPC from the RPC client, the RPC categories get many query options like this. And now you would have the data and you no longer have to use the one from the props. The only, you know, you have to make sure that you do these changes here, because data can now be optional. So current categories here might be this. Let me just see current categories.
Current categories, what is it saying for data? Use query result. Current categories, custom category. Oops. I think this should work just fine.
Let me try it now. So now, the fact that we are passing it, but OK, so it seems like it's not working. So Maybe I'm just trying my best to understand how we can do this. I think this is data. Yeah.
My apologies. I have to destructure the data. Make sure you destructure the data. So what's going on now, and let's see. Okay, this, you can also ignore this.
This is because here in the app folder we did is loading. You can remove that. It's a hydration error. Don't worry about it. The reason I say don't worry about it is because A, we just did this to test out B, because hydration errors will be solved in another way here, right?
So don't worry. Okay. So now when I click View All, this actually loads independently. So for example, here, when you click, you can't really see it because it loads super fast, right? But if you want to, yeah, you can do that.
And then you can remove the data from here, you can remove the data from here as well, like this. You basically don't need the data anymore from the category sidebar, and all the places you use it, you can remove the data now. It's a way to reduce prop drilling, right? And also in the search input, you no longer need data in the search input at all. I feel like this is simpler.
So now your search input, which you use inside of, let me close everything so you can see, inside of the search filters folder index, you no longer have to pass the data to the search input. You have to pass it to the categories because that's where we use it, right? So let me just separate these imports like this. And now, even though we don't pass the data, you can see that we still load this here. If you want, you can go inside of categories here, and you can add a special loading case, if you will, or you don't have to.
It's just gonna be empty until something loads. I think that's okay. Great. But one loading that I do not like is this one. It hurts your eyes to look at it.
So what I think that we can do is just build this very fast loading state here for the search filters. So export const search filters loading And you can return pretty much the same stuff. Make sure this is disabled like this. And make sure for this, you just give it a div with a class name height of 10 or whatever the height of our buttons are. But I think height 10 will look just fine.
It doesn't have to be perfect. And in here, you also have to give this a style, background color. And you'd want to give this, let me just see. So I'm not sure if you understand what this is at the moment, that's because this is from a feature we have not implemented yet, I think. But yeah, Later on, when we click on drawing and painting and we redirect, and this isn't a 404, this will be in the color of that category.
So that's why we have to specify the background color for the loading, right? So now that you have search filters loading, if you want to, you can go back inside of the layout here, and you can pass that here. Like this, Search Filters Loading from Search Filters. And now, when you do a hard refresh, you can see how the loading state looks like, right? There isn't too much flashing.
It still looks like it moves a tiny bit. I think that's because categories, and I think the individual category drop down button uses height 11. So maybe we have to change the search filters loading to 11. There we go. Now there's almost no jumping at all, except this part, which is before we calculate which items to show and which items to hide.
Great. So I'm super, super satisfied with this. You can decide a convention for yourself. Are you going to call this loading, or Are you going to call this loading or are you going to call this skeleton? If you're going to call it skeleton, make sure you change it to skeleton here as well.
I think I'm going to go with skeleton actually. I like the skeleton. And yeah, I like how this looks like. It's disabled for a second, but then it goes back. Great.
So I'm super happy with this. And one thing I want to do inside of the search filters. So I also want to give this a style here and the background color of this. So that's the default color that will be for this. If you're wondering why am I putting it in a style, because later it's going to be dynamic.
That's the only reason. So yes, I want it to be a little bit darker than this. So now you can't even notice the loading state besides that this is disabled for a second. Great. I am super, super satisfied with how this turned out.
And now one thing you can do is you can go ahead and learn how to, let me just see, I think somewhere here, they gave instructions on how to infer the output of something. So you can infer an output for a specific procedure here. Let's try and do that. Oh, this uses DRPC like this. OK.
Let's see if we can do that or maybe there's a smarter way. Just a second. So I'm gonna go and do this. I'm gonna go inside of source modules categories and I'm gonna create types here. I'm going to import inferrouter outputs from trpc server and import app router from at trpc routers underscore app.
So basically this definition. And we can be more specific, so I just need to type. And then export type categories get many output. Infer router outputs as in the app router. And then in here, categories, get many, like this.
And then in here, we can export type categories, get many output single. Or I don't know. Yeah, we can do single. And then this would be this, and then a number inside. And then that would be like the single result.
And you can then use this to replace all instances of custom category. So let's say we use custom category here. And now we can use categories get many output here. And this can be categories. But we can just repeat it.
And I think it's easier to use a number here. And you can see the types are all correct still. Let's see where do I use custom category. I use it here. So categories get many output and like an item inside and this will be categories get many output.
I think the types are fully correct. It's nice when things work. Let me just align this here. Let me move this here like this. So I think the types work here.
Let's see where else do we have it. We have it inside of categories.psx. So I'll remove this here. And the data here will be categories, get many output from modules. And that's it.
We don't have to change absolutely anything because all of our data is already compatible. And we now have category dropdown in the search filters. So I'm going to remove this. And this will be categories, get many outputs, and then choose one item inside so it knows it's a single item here. I'm not sure if this is the best way to do it, but it works.
And again, everything works, no errors at all. And one more place, subcategory menu inside of the search filters. There we go. So this will be categories, get many output, and then a single result inside. And that's it.
Fixed. And all that's left is to remove the types.ts from your app folder search filters, where you had that custom type. But leave this one, of course. And then, since we never used a single one, we can hide it. There we go.
Now we have all the places where you use the categories getManyOutput, and it's directly inferred from tRPC, so you don't have to worry. And yeah, in the next chapter, I'm going to see if this is the best way to get the single item type. Maybe there's a smarter way to do it. Great. I think that wraps it up for this chapter.
I'm super satisfied with everything we did. So we prefetched the categories, we client-side fetched the categories in the sidebar, and we inferred the TRPC types. We did literally all of those things. So now let's push to GitHub, 07-TRPC-integration. So What I'm doing is I'm going to shut down the app, git checkout b 07-trpc-integration.
Let me just double check. OK. Git add, git commit 07-trpc-integration. Like this. Git push origin 07-trpc-integration.
There we go so as you can see now I am on the new branch here you can see the new branch here and as always you can see on the graph that I have detached now from my main master branch. So now I'm going to go ahead inside of my GitHub here. I'm going to open a pull request here. Create a pull request. And let's go ahead and see what our reviewer has to say about this.
And here we go! The walkthrough. This pull request introduces a new VS Code configuration for TypeScript. It also removes and updates dependency versions in the package file. Several Home components have been refactored to use TRPC with React Query for data fetching, replacing prop-based data with asynchronous query hooks and adding skeletal loading states.
New TRPC client server and API route files have been added to consolidate the TRPC architecture. In addition, category-related procedures and types have been updated to use a new structure and an obsolete type definition file has been removed. Exactly what we did. Perfect. I'm super satisfied with how that turned out.
And in here you can also see a sequence diagram. So if you are interested in how our TRPC configuration actually works, you can see it right here. I'm actually super impressed by this. Great. So now You can also see some comments left here.
:03 And perhaps this one is something we should do. Consider enabling the SuperJSON transformer. And I think we should actually do that before we merge. So let's go ahead and do this. So SuperJSON, let's see all the places where we use it.
:24 So the first place is inside of the RPC client. We use it, so we want it. And we need to import superjson from superjson. I'm just going to do it here. There we go.
:45 Maybe I need to destructure it. Okay, I think this is now an error because I have other places where I need to add it. Let's go inside of the init here. I think I need to allow super JSON here. So add import super JSON from super JSON.
:05 There we go. So I need it here in my init file. And now this error goes away because it's properly inferred. Let's see inside of query.client, serialize data, super.json.serialize, and hydrate, super.json.deserialize. And we can leave this import now.
:24 There we go. That's another place. And let's see the server here. The server does not use SuperJSON. So I think that now we're using SuperJSON in all places.
:36 So we've modified three components now after our commit. The client.tsx in the trpc, which now uses the SuperJSON transformer. The init file, which uses the super JSON transformer, and the query client, which serializes data and deserializes it in super JSON now. So I suggest you do that for the reason it wrote here. It is typically recommended for TRPC implementations to properly serialize dates, big integers, and other complex types.
:07 Without it, you might encounter issues with these data types. So let's absolutely do that. These I'm not going to do. I'm satisfied with how it is at the moment. And this is just a mock context so it can stay this way.
:23 So instead of merging, I mean, if you merged, it's okay, you can just push to master. It's not a big problem. So let's go ahead and do 07 PRPC integration fix. And then I'm going to do git push. You can also push and master right if you already decided to merge, it's not a problem.
:47 But what I'm going to do is I'm just going to refresh this, wait for this to receive my new changes, and then I'm going to go ahead and merge. And there we go. So after I pushed the new fix, we can see that it has some duplicate comments right here with a fallback right here. It's nice. So the more code you give it, the more comments it tells you to do.
:14 And I think that now if you take a look at where it commented out you can see how it immediately marked the super JSON as outdated and it also marked that it has been addressed in a future commit so that's pretty cool like you're talking to an actual reviewer great I'm satisfied with what it currently is, so I'm going to merge my changes here. So I'm not going to delete my branch. And now let me just double check. In here I now have 0.7 tRPC integration. Great.
:46 And as always, we now have to go back to our branch here. So that's going to be the master or the main branch. So either this or main, right. And then let's just do git pull origin master or main. And there we go.
:04 That's it. You can take a look at your graph. And it should be something like this. So I had two commits in this branch before I merged back to master branch. As always, please ensure that you are on the master branch and you are up to date.
:21 You can also run your app to confirm everything is fine. So you are ready for the next chapter. And now we can officially mark this as well. Amazing, amazing job.