跳至主要內容

一篇標記為「trpc」的文章

檢視所有標籤

· 閱讀 5 分鐘
Alex / KATT 🐱

我是 Alex,或 GitHub 上的「KATT」,我想告訴你一個名為 tRPC 的函式庫。我尚未發布任何相關文章,所以我只是寫這篇簡介來開始進行(但我們在 GitHub 上已經不知不覺獲得了 >530 🌟)。期待文章和影片簡介的到來!如果你想保持最新狀態或想提問,可以在 Twitter 上追蹤我 @alexdotjs

簡而言之,tRPC 為你提供從(節點)伺服器到客戶端的端對端類型安全性,甚至不需要宣告類型。你只需要在後端在函式中傳回資料,而在前端則根據端點名稱使用所述資料。

以下是執行 tRPC 端點和客戶端呼叫時的樣子: 替代文字

我已經為 React 建立了一個函式庫(@trpc/react),它建立在出色的 react-query 之上,但客戶端函式庫(@trpc/client)可以在沒有 React 的情況下使用(如果你想建立特定的 Svelte/Vue/Angular/[..] 函式庫,請與我聯繫!)

不涉及任何程式碼產生,而且你可以很輕鬆地將它新增到現有的 Next.js/CRA/Express 專案中。

範例

以下是稱為 hello 的 tRPC 程序(又稱端點)範例,它會接收 字串 參數。

tsx
const appRouter = trpc.router().query('hello', {
input: z.string().optional(),
resolve: ({ input }) => {
return {
text: `hello ${input ?? 'world'}`,
};
},
});
export type AppRouter = typeof appRouter;
tsx
const appRouter = trpc.router().query('hello', {
input: z.string().optional(),
resolve: ({ input }) => {
return {
text: `hello ${input ?? 'world'}`,
};
},
});
export type AppRouter = typeof appRouter;

以下是使用所述資料的類型安全客戶端

tsx
import type { AppRouter } from './server';
async function main() {
const client = createTRPCClient<AppRouter>({
url: `https://127.0.0.1:2022`,
});
const result = await client.query('hello', '@alexdotjs');
console.log(result); // --> { text: "hello @alexdotjs" }
}
main();
tsx
import type { AppRouter } from './server';
async function main() {
const client = createTRPCClient<AppRouter>({
url: `https://127.0.0.1:2022`,
});
const result = await client.query('hello', '@alexdotjs');
console.log(result); // --> { text: "hello @alexdotjs" }
}
main();

這就是獲得類型安全所需的全部! result 會根據後端在函式中傳回的內容進行類型推論。輸入的資料也會根據驗證器的傳回值進行推論,因此資料可以直接安全使用 - 實際上,你必須透過驗證器傳遞輸入資料(而且 tRPC 與 zod/yup/自訂驗證器開箱即用)。

以下是 CodeSandbox 連結,你可以使用連結中的範例:https://githubbox.com/trpc/trpc/tree/next/examples/standalone-server(查看終端機輸出,而不是預覽!)

什麼?我正在從後端匯入程式碼到我的用戶端? - 不,你實際上沒有

即使看起來像這樣,也沒有任何程式碼從伺服器共用至用戶端;TypeScript 的 import type "[..] 只匯入宣告,用於類型註解和宣告。它總是會被完全刪除,因此在執行階段沒有任何殘留。" - TypeScript 3.8 中新增的功能 - 查看 TypeScript 文件

沒有涉及程式碼產生,只要你有方法從伺服器共用類型至用戶端,你就可以在今天將此功能新增至你的應用程式(希望你已經在使用單一儲存庫)。

但我們才剛開始!

我之前提到有一個 React 函式庫,在 React 中使用上述資料的方法如下

tsx
const { data } = trpc.useQuery(['hello', '@alexdotjs']);
tsx
const { data } = trpc.useQuery(['hello', '@alexdotjs']);

.. 而且你會在用戶端取得類型安全的資料。

你可以使用現有的舊專案新增 tRPC(有 Express/Next.js 的轉接器),它與 CRA 搭配使用效果很好,也應該適用於 React Native。它甚至不與 React 綁定,因此如果你想建立 Svelte 或 Vue 函式庫,請與我聯繫。

變異資料呢?

變異就像查詢一樣簡單,它們在底層實際上是相同的,但只是以不同的語法糖方式公開,並產生 HTTP POST 而不是 GET 要求。

以下是一個使用資料庫的稍微複雜的範例,取自 todomvc.trpc.io 中的 TodoMVC 範例 / https://github.com/trpc/trpc/tree/next/examples/next-prisma-todomvc

tsx
const todoRouter = createRouter().mutation('add', {
input: z.object({
id: z.string().uuid(),
data: z.object({
completed: z.boolean().optional(),
text: z.string().min(1).optional(),
}),
}),
async resolve({ ctx, input }) {
const { id, data } = input;
const todo = await ctx.task.update({
where: { id },
data,
});
return todo;
},
});
tsx
const todoRouter = createRouter().mutation('add', {
input: z.object({
id: z.string().uuid(),
data: z.object({
completed: z.boolean().optional(),
text: z.string().min(1).optional(),
}),
}),
async resolve({ ctx, input }) {
const { id, data } = input;
const todo = await ctx.task.update({
where: { id },
data,
});
return todo;
},
});

React 用法如下所示

tsx
const addTask = trpc.useMutation('todos.add');
return (
<>
<input
placeholder="What needs to be done?"
onKeyDown={(e) => {
const text = e.currentTarget.value.trim();
if (e.key === 'Enter' && text) {
addTask.mutate({ text });
e.currentTarget.value = '';
}
}}
/>
</>
)
tsx
const addTask = trpc.useMutation('todos.add');
return (
<>
<input
placeholder="What needs to be done?"
onKeyDown={(e) => {
const text = e.currentTarget.value.trim();
if (e.key === 'Enter' && text) {
addTask.mutate({ text });
e.currentTarget.value = '';
}
}}
/>
</>
)

結束,目前為止。

無論如何,正如我所說,我只是想讓球滾動。還有很多事情

  • 建立用於使用者特定資料的傳入請求的內容,這些資料會注入相依性至解析器中 - 連結
  • 路由器的中間軟體支援 - 連結
  • 合併路由器(你可能不想要將所有後端資料放在一個檔案中) - 連結
  • 使用我們的 @trpc/next 適配器在 React-land 中見過的最簡單的伺服器端渲染 - 連結
  • 類型安全的錯誤格式化 - 連結
  • 資料轉換器(透過網路使用 Date/Map/Set 物件) - 連結
  • React Query 的輔助工具

如果你想要開始,在 Next.js 入門 中有幾個範例。

在 Twitter 上追蹤我以獲得更新!