Hello everyone!
welcome back, in our first session we had implemented our backend server of the tRPC apis where we built a simple server that fetches books from some datasource and returns that in json format. We also tested our aplication and it worked fine. In this section, we are going to build our frontend that interacts with our backend server, fetches data and displays it in our app. To do this, I will be building a simple React application using vite.
Prerequisites
- Part 1 of our session. Feel free to build your own
- Typescript
- React knowledge
Let us begin.
From our introduction, we mentioned that tRPC implements typesafe Remote Procedural Call and this basically means it allows a machine from one side to call another procedure or function from another machine. The typesafe bit means it leverages typescript for typesafety. This helps in code building and productivity boost during application development. Let us start developing our application
We had created a folder where we put two folders, trpc-backend
and trpc-frontend
. For now, navigate to the frontend folder and run the following command.
$ pnpm vite@latest
Follow the prompt, I will also be using typescript. You should be getting something like this in the folder. However, feel free to develop it how you like.
Now let us continue with development, I will be using TailwindCSS
for some styling and React Query
for our state management. So let us initialize our application with tailwind.
$ pnpm add -D tailwindcss postcss autoprefixer
$ npx tailwindcss init -p
$ pnpm add react-query
$ pnpm add @trpc/client
With this, let us to our index.css
file, comment all the code add the following.
@tailwind base;
@tailwind components;
@tailwind utilities;
Replace the code in the
`tailwind.config.js
with this
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
Now our application can use TailwindCSS.
In our
file, we need to wrap with
main.tsx
react-query
to make our state available for every component, to do so, paste the following
import App from './App.tsx'
import './index.css'
import { QueryClient, QueryClientProvider, } from 'react-query';
const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</React.StrictMode>,
)
Now react-query
will be available for our application.
Now let us go to our App.tsx
file and add the following.
Here is where we will handle the state logic and the fetching logic. tRPC
changed alot from version 9. So the documentation for integrating with react also changed.
import { AppRouter } from '../../trpc-backend/src/trpc/trpc';
import { createTRPCProxyClient, httpBatchLink} from '@trpc/client'
function App(){
const trpcClient= createTRPCProxyClient<AppRouter>({
links:[
httpBatchLink({
url: 'http://localhost:3000/trpc',
}),
]
});
}
Let us go through this, here we imported the
type we had exported from our backend server, then we import the
AppRouter
httpBatchLink
and createTRPCProxyClient
from the client library. We then set the link to the backend server and that is it. Now are ready to interact with our server data.
Next we import the functions that help up query
import { useMutation, useQuery, useQueryClient } from 'react-query';
import { AppRouter } from '../../trpc-backend/src/trpc/trpc';
import { createTRPCProxyClient, httpBatchLink} from '@trpc/client'
type Book={
id: number,
title: string,
img: string,
description: string,
price: number
author: string
}
function App(){
const {data,isLoading, isError,} = useQuery({
queryKey: ['books'],
queryFn: async () => await trpcClient.getBooks.query(),
})
const trpcClient= createTRPCProxyClient<AppRouter>({
links:[
httpBatchLink({
url: 'http://localhost:3000/trpc',
}),
]
});
if(isLoading) return <div>Loading...</div>
if(isError) return <div>Error</div>
return (
<div>
<h1 className="text-3xl font-bold">React tRPC and react query</h1>
<div className='grid grid-cols-2 gap-1 md:grid md:grid-cols-3 md:gap-2'
>
{
data?.map((item: Book)=>{
return (
<div key={item.id} className='border-2 border-gray-200 rounded-md p-2 hover:bg-sky-500 transition ease-in-out delay-150'>
<img src={item.img} alt={item.title} className='w-32 h-32'/>
<h2 className='text-xl font-bold'>{item.title}</h2>
<p className='text-sm'>{item.description.slice(0,50)}...</p>
<p className='text-sm font-bold'>${item.price}</p>
</div>
)
})
}
</div>
</div>
)
}
With this code, we have just
Top comments (0)