Skip to main content

使用 Next.js + React 技术栈构建现代 Web 应用

· 6 min read
Kevin
Kevin
Web3 Engineer @CatFee

Technology Stack

随着前端技术的飞速发展,构建高效、现代化的 Web 应用变得愈发重要。本文将围绕 Next.jsReactshadcnTailwindCSSZodZustandReact Queryopenapi-react-query 的技术栈,分享一个完整的开发方案。


1. 技术栈简介

Next.js

一个基于 React 的框架,支持服务端渲染 (SSR)、静态站点生成 (SSG) 和全栈开发。它提升了 SEO 能力,并优化了性能。

React

现代化的组件式前端开发库,是构建用户界面的核心工具。

shadcn

一个整合了 Radix UI 和 TailwindCSS 的组件工具库,提供丰富的 UI 基础组件。

TailwindCSS

一种实用的 CSS 框架,通过类名快速构建响应式、现代化的 UI。

Zod

一个类型安全的验证库,用于校验表单数据或 API 请求数据,完美配合 TypeScript。

Zustand

轻量级状态管理工具,适合管理复杂但局部的应用状态。

React Query

服务器状态管理工具,处理数据获取、缓存、同步及更新。

openapi-react-query

基于 OpenAPI 规范生成类型安全的 React Query API 客户端,提升开发效率和安全性。


2. 快速项目初始化

2.1 创建 Next.js 项目

使用 TypeScript 初始化项目:

npx create-next-app@latest my-nextjs-app --typescript
cd my-nextjs-app

2.2 安装依赖

安装技术栈中的核心库:

npm install tailwindcss postcss autoprefixer zustand @tanstack/react-query zod openapi-react-query
npm install @shadcn/ui

2.3 配置 TailwindCSS

初始化 TailwindCSS 配置文件:

npx tailwindcss init

修改 tailwind.config.js

module.exports = {
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
"./app/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
};

styles/globals.css 中引入 TailwindCSS:

@tailwind base;
@tailwind components;
@tailwind utilities;

2.4 集成 React Query

创建 React Query 客户端:

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const queryClient = new QueryClient();

export default function App({ Component, pageProps }: any) {
return (
<QueryClientProvider client={queryClient}>
<Component {...pageProps} />
</QueryClientProvider>
);
}

2.5 配置 openapi-react-query

根据 OpenAPI 规范生成 API 客户端:

npx openapi-codegen generate --input ./path-to-openapi.json --output ./generated --client react-query

在项目中提供 API 配置:

import { createClient, ApiProvider } from "./generated";

const apiClient = createClient({
baseUrl: "https://api.example.com",
fetch: async (url, options) => {
// 你可以在这里添加认证逻辑,例如添加 Token 到请求头
const token = "your-auth-token";
return fetch(url, {
...options,
headers: {
...options.headers,
Authorization: `Bearer ${token}`,
},
});
},
});

export default function App({ Component, pageProps }: any) {
return (
<ApiProvider client={apiClient}>
<Component {...pageProps} />
</ApiProvider>
);
}

3. 表单开发:结合 shadcn 和 Zod

以用户注册表单为例,展示如何结合 shadcn 和 Zod 构建类型安全、用户友好的表单。

3.1 定义验证规则

import { z } from "zod";

const userSchema = z.object({
name: z.string().min(1, "Name is required"),
email: z.string().email("Invalid email address"),
password: z.string().min(6, "Password must be at least 6 characters"),
});

export type UserFormValues = z.infer<typeof userSchema>;

3.2 构建表单组件

import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from "@/components/ui/form";

export default function UserForm() {
const form = useForm<UserFormValues>({
resolver: zodResolver(userSchema),
defaultValues: {
name: "",
email: "",
password: "",
},
});

const onSubmit = (values: UserFormValues) => {
console.log("Submitted values:", values);
};

return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
<FormField
name="name"
control={form.control}
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input placeholder="Your name" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
name="email"
control={form.control}
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input type="email" placeholder="Your email" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
name="password"
control={form.control}
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<Input type="password" placeholder="Your password" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Register</Button>
</form>
</Form>
);
}

4. 状态管理:使用 Zustand

通过 Zustand 管理应用状态,例如全局用户数据:

import create from "zustand";

interface UserState {
user: { name: string; email: string } | null;
setUser: (user: { name: string; email: string }) => void;
}

export const useUserStore = create<UserState>((set) => ({
user: null,
setUser: (user) => set({ user }),
}));

在组件中使用 Zustand:

import { useUserStore } from "@/store/user";

export default function Profile() {
const user = useUserStore((state) => state.user);

return (
<div>
{user ? <p>Welcome, {user.name}!</p> : <p>Please log in.</p>}
</div>
);
}

5. 总结