概要:
tRPC試すメモとなります。 TypeScriptが使えて便利そうでした
※ 情報が少なめで難航しました。。
-
server: express + trpc/server
-
client : React
構成
- trpc/server : 10.13.2
- express : 4.18.2
- React 18.2.0
参考
参考のコード
Server
- install
npm install --save express cors @trpc/server zod
npm install --save-dev typescript nodemon ts-node @types/express @types/node @types/cors
-
server/index.ts
-
const appRouter : ルーティング定義ぽいです。export してます
index.ts
import express from 'express';
import { initTRPC } from '@trpc/server';
import * as trpcExpress from '@trpc/server/adapters/express';
import cors from 'cors';
import { z } from 'zod';
const app = express();
const PORT = 3000;
app.use(cors());
const t = initTRPC.create();
const router = t.router;
const publicProcedure = t.procedure;
//type
interface User {
id: string;
name: string;
}
const userList: User[] = [
{
id: '1',
name: 'KATT',
},
];
//
const appRouter = router({
hello: t.procedure.query(() => {
return 'Hello World-1234';
}),
helloName: t.procedure
.input(z.object({ name: z.string(), age: z.number() }))
.query(({ input }) => {
return {
name: `Hello World ${input.name}`,
age: input.age,
};
}),
userById: publicProcedure
.input((val: unknown) => {
if (typeof val === 'string') return val;
throw new Error(`Invalid input: ${typeof val}`);
})
.query((req) => {
const input = req.input;
const user = userList.find((it) => it.id === input);
return user;
}),
userCreate: publicProcedure
.input(z.object({ name: z.string() }))
.mutation((req) => {
const id = `${Math.random()}`;
const user: User = {
id,
name: req.input.name,
};
userList.push(user);
return user;
}),
});
app.get('/', (_req, res) => res.send('hello'));
app.use(
'/trpc',
trpcExpress.createExpressMiddleware({
router: appRouter,
})
);
app.listen(PORT, () => console.log(`Example app listening on port ${PORT}!`));
export type AppRouter = typeof appRouter;
Client
-
install, vite使う例です
-
⇒React, TypeScript 選びました。
npm create vite@latest client
npm install @trpc/client @trpc/server @trpc/react-query @tanstack/react-query
- tree
$ cd client
$ tree
.
├── index.html
├── package.json
├── public
│ └── vite.svg
├── src
│ ├── App.css
│ ├── App.tsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ └── Test.tsx
│ ├── index.css
│ ├── main.tsx
│ ├── utils
│ │ └── trpc.ts
│ └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
-
utils/trpc.ts
-
server側の、AppRouter読みます
import { createTRPCReact } from '@trpc/react-query';
import type { AppRouter } from '../../../server';
export const trpc = createTRPCReact<AppRouter>();
- App.tsx
App.tsx
import { useState } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { httpBatchLink } from '@trpc/client';
import { trpc } from './utils/trpc';
import Test from './components/Test';
function App() {
const [queryClient] = useState(() => new QueryClient());
const [trpcClient] = useState(() =>
trpc.createClient({
links: [
httpBatchLink({
url: 'http://localhost:3000/trpc',
}),
],
})
);
return (
<trpc.Provider client={trpcClient} queryClient={queryClient}>
<QueryClientProvider client={queryClient}>
<Test />
</QueryClientProvider>
</trpc.Provider>
);
}
export default App;
- components/Test.tsx : 画面
- useQueryで、取得の処理です
Test.tsx
import { trpc } from '../utils/trpc';
const Test = () => {
const hello = trpc.hello.useQuery();
console.log(hello.data);
const test = trpc.helloName.useQuery({ name: 'John', age: 21 });
console.log(test.data);
const user = trpc.userById.useQuery('1');
console.log(user.data);
if(test.data === undefined ) { return; }
if(user.data === undefined ) { return; }
return (
<div>
<h3>react_trpc2/Test.tsx</h3>
<hr />
hello : {hello.data}
<hr />
test:<br />
name: {test.data.name} , age: {test.data.age}
<hr />
User:<br />
id: {user.data.id}, name: {user.data.name}
</div>
);
};
export default Test;
....