这个 TypeScript 库帮助我更快地构建全栈应用程序
我以前开发 Web 应用的时候,通常都是用同样的方式。我会用 Node.js 和 Express 搭建后端,创建标准的 REST API 端点。虽然能用,但感觉就像在重复做同样的事情。
对于每个新功能,我必须:
- 在服务器上定义 API 路由。
- 弄清楚路线所需的数据类型以及它将发回的数据类型。
- 转到前端代码(通常是 React)并编写代码来调用特定的 API 路由。
- 在前端再次定义类型,以便它知道需要什么数据。
- 通常,我需要像 Redux 这样的额外工具来管理获取数据、显示加载微调器以及处理 React 中的错误。
这意味着我在两个地方拥有相同的 API 信息(路径、数据类型):后端和前端。如果我在后端做了一些更改——比如让 API 返回不同的数据——我必须记住更新前端代码。如果我忘记了,事情就会崩溃。作为一个试图快速构建项目的单人团队,保持所有东西都匹配起来既慢又烦人。
我是一名独立开发者,正在开发UserJot,我需要一种更好的方法来快速开发,确保一切正常,并保持代码简洁。所以,找到一个能让这一切变得更容易的方法对我来说意义重大。
寻找更简单的方法:tRPC
后来,在 2023 年,我偶然发现了一个名为 tRPC 的 TypeScript 库。它的核心理念听起来很棒:如果你的前端代码可以直接调用后端代码,就像调用普通函数一样,而且所有数据类型都会自动匹配,那会怎么样?我不确定这是否只是炒作,但听起来很有趣,值得一试。我花了大约一周的时间在一个小项目上试用它。
说实话?它让我的事情变得简单多了,快捷多了。
工作原理:快速浏览
使用 tRPC,您实际上不必以相同的方式考虑 REST 端点。相反,您可以在后端创建“过程”。将它们视为前端可以调用的函数。您可以使用 Zod 等辅助库来明确定义哪些类型的数据进入这些过程以及输出哪些数据。
这是一个基本的想法:
后端(服务器代码):
// server.ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod'; // Zod helps define types
const t = initTRPC.create();
// Define the functions our frontend can call
export const appRouter = t.router({
// A procedure to get user data
getUser: t.procedure
.input(z.object({ userId: z.string() })) // Needs a userId string
.query(({ input }) => {
// Code to find the user...
return { id: input.userId, name: 'Example User' }; // Returns user object
}),
// A procedure to create a new user
createUser: t.procedure
.input(z.object({ name: z.string() })) // Needs a name string
.mutation(({ input }) => {
// Code to create the user...
return { id: 'newUser123', name: input.name }; // Returns new user
}),
});
// Export the type of our router
export type AppRouter = typeof appRouter;
这里我们创建了两个过程:getUser
和createUser
。Zod 检查输入数据。重要的部分是导出AppRouter
类型——这会告诉 TypeScript 我们的 API 到底是什么样子。
前端(使用 React 的客户端代码):
tRPC 与 React Query 等前端工具配合得很好。你可以在前端设置一个 tRPC 客户端,并告诉它AppRouter
你从后端导出的类型。
// client.tsx (React example)
import { createTRPCReact } from '@trpc/react-query';
import type { AppRouter } from './server'; // Import the type from the backend!
const trpc = createTRPCReact<AppRouter>();
function UserProfile() {
// This hook knows exactly what 'getUser' needs and returns!
const userQuery = trpc.getUser.useQuery({ userId: '123' });
if (userQuery.isLoading) return <div>Loading...</div>;
if (userQuery.error) return <div>Error: {userQuery.error.message}</div>;
// We know `userQuery.data` has a `name` property because of tRPC!
return <div>User Name: {userQuery.data.name}</div>;
}
function CreateUserButton() {
const mutation = trpc.createUser.useMutation();
const handleCreate = () => {
// tRPC checks if we're sending the right input (`{ name: string }`)
mutation.mutate({ name: 'New User' });
};
return <button onClick={handleCreate} disabled={mutation.isLoading}>Create User</button>;
}
看到前端是如何导入AppRouter
类型的了吗?正因为如此,trpc.getUser.useQuery
钩子会自动知道它需要一个userId
,并且它将data
包含一个id
和name
。你无需再在客户端为 API 数据编写获取调用或类型定义。它自己知道!
对我来说真正好转的是什么
使用 tRPC 解决了我的主要难题:
- 构建速度更快:我不再需要重复编写相同的 API 信息。在后端创建函数意味着它可以立即在前端完成并输入。这让我能够更快地构建功能。
- 更少的 Bug:由于类型是共享的,如果我搞砸了什么,TypeScript 会立即通知我。如果我修改了后端函数以返回不同的数据,我的前端代码会在我运行应用程序之前立即在编辑器中显示错误。
- 编码更轻松:我的代码编辑器可以正确地自动完成前端 API 调用。而且,由于 tRPC 与 React Query 等工具配合良好,它们可以轻松处理数据获取的所有棘手部分(例如缓存和加载状态)。我不再需要仅仅为了处理服务器数据而使用 Redux 了。
我现在如何使用它
我现在几乎把 tRPC 用在所有东西上,包括UserJot的整个后端。当我编写像 这样的后端程序时createSubmission
,我就能立即在前端获得易于使用、类型安全的函数。它不仅适用于小玩具;它非常适合构建大规模的实际应用程序。
当 tRPC 可能不合适时
当你同时控制前端和后端,并且两者都使用 TypeScript(或 JavaScript)时,tRPC 非常棒。它能很好地将它们结合在一起。
但是,如果你正在构建一个供其他人使用的 API (公共 API),那么 REST 或 GraphQL 之类的语言可能更好。这些是不同系统(你无法控制)之间通信的更标准的方式。
也许可以尝试一下?
如果你正在使用 TypeScript 构建全栈应用,并且觉得在保持前后端类型同步上花费了太多时间,不妨考虑一下 tRPC。它确实让我的开发过程更加顺畅和快捷——尤其是在构建和扩展像UserJot这样的工具时,因为我没时间浪费在重复类型或调试不匹配的问题上。
此外,如果您正在寻找客户反馈工具,我正在构建UserJot,并希望听到您的想法。
鏂囩珷鏉ユ簮锛�https://dev.to/shayy/this-typescript-library-helped-me-build-full-stack-apps-faster-3mc3