Administrator
发布于 2024-10-20 / 8 阅读
0
0

Next.js 零基础教程15 实现 Server Action 功能

在上一章中,您使用 URL 搜索参数和 Next.js API实现了搜索和分页。让我们继续处理发票页面,添加创建、更新和删除发票的功能!

在本章中,我们将要讨论几个主题:

  • React Server Actions 是什么以及如何使用它们来改变数据。

  • 如何使用表单和服务器组件。

  • 使用本机formData对象的最佳实践,包括类型验证。

  • 如何使用revalidatePath API 重新验证客户端缓存。

  • 如何创建具有特定 ID 的动态路线段。

创建 Server Action

"创建服务器操作"(Create a Server Action)是指在Next.js应用程序中创建一个在服务器端执行的函数,用于处理表单提交或其他客户端操作。

  1. 服务器操作的定义

    服务器操作是在服务器端执行的异步函数,可以直接从客户端组件中调用。它们允许您在不创建 API 路由的情况下执行服务器端逻辑。

  2. 主要特点

    • 可以直接在服务器上执行数据库查询或其他服务器端逻辑

    • 可以从客户端组件中无缝调用

    • 提供了内置的数据验证和错误处理机制

    • 支持渐进式增强,可以在禁用 JavaScript 的情况下工作

  3. 创建方法
    通常,您可以在服务器组件或单独的文件中定义服务器操作,然后将其导入到客户端组件中使用。创建服务器操作可以帮助您更有效地处理表单提交和其他需要服务器端处理的操作,同时保持代码的简洁性和安全性。

理解完概念,接着上一章的代码结构,导航到lib目录并创建一个名为actions.ts文件,在此文件的顶部,添加 Reactuse server指示:

通过添加'use server',您可以将文件内的所有导出函数标记为服务器操作。然后可以导入这些服务器函数并将其用于客户端和服务器组件。"use server"您也可以通过在操作中添加来直接在服务器组件中编写服务器操作。但在本课程中,我们将把它们全部组织在一个单独的文件中。

在您的actions.ts文件中,创建一个接受以下内容的新异步函数formData:

'use server';
export async function createInvoice(formData: FormData) { }

然后,在您的组件中,从文件中<Form>导入,向元素添加属性,然后调用操作。

来到提交页面,http://172.16.100.104/dashboard/invoices/create点击提交,可以看到参数已经传到到actions.ts当中。

需要了解:在 HTML 中,您需要将URL传递给action属性。此URL将是提交表单数据的目的地(通常是 API 端点)。然而,在 React 中,该action属性被视为一种特殊的 prop - 这意味着 React 在其之上构建以允许调用操作。在后台,服务器操作会创建一个POST API 端点。这就是为什么您在使用服务器操作时不需要手动创建 API 端点的原因。

回到/app/lib/actions.ts文件,需要提取的值formData,有几种方法您可以使用。在这个例子中,我们使用.get(name)方法。

'use server';

export async function createInvoice(formData: FormData) {
    const rawFormData = {
        customerId: formData.get('customerId'),
        amount: formData.get('amount'),
        status: formData.get('status'),
    };
    // Test it out:
    console.log(rawFormData);
}


要检查所有东西是否连接正确,请继续尝试表单。提交后,您应该会在终端中看到刚刚输入到表单中的数据,现在数据已经是对象的形状了,处理起来会更加容易。

验证并准备数据

在将表单数据发送到数据库之前,需要确保其格式正确且类型正确。在我们前面章节有实现发票的数据结构,发票表需要以下格式的数据:

export type Invoice = {
  id: string; 
  customer_id: string;
  amount: number; 
  status: 'pending' | 'paid';
  date: string;
};

可以观察刚刚的返回,到目前为止只有表格中的customer_id、amount、status的字段。

类型验证和强制
验证表单中的数据是否与数据库中的预期类型一致非常重要。例如,如果您console.log在操作中添加以下内容:

console.log(typeof rawFormData.amount);


您会注意到amount是类型string而不是number。这是因为input带有的元素type="number"实际上返回的是字符串,而不是数字。
要处理类型验证,您有几个选择。虽然您可以手动验证类型,但使用类型验证库可以节省您的时间和精力。为了举例说明,我们将使用Zod,一个TypeScript优先的验证库,可以为您简化此任务。

在您的actions.ts文件中,导入Zod并定义与表单对象形状相匹配的架构。此架构将formData在将其保存到数据库之前对其进行验证。Zod 如果不存在,则需要通过pnpm install Zod进行安装使用。

'use server';
import { z } from 'zod';
import { query } from '@/app/lib/db';
import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';

const FormSchema = z.object({
    id: z.string(),
    customerId: z.string(),
    amount: z.coerce.number(),
    status: z.enum(['pending', 'paid']),
    date: z.string(),
});

const CreateInvoice = FormSchema.omit({ id: true, date: true });

export async function createInvoice(formData: FormData) {
    const { customerId, amount, status } = CreateInvoice.parse({
        customerId: formData.get('customerId'),
        amount: formData.get('amount'),
        status: formData.get('status'),
    });
    const amountInCents = amount * 100;
    const date = new Date().toISOString().split('T')[0];

    try {
        await query(
            'INSERT INTO invoices (customer_id, amount, status, date) VALUES ($1, $2, $3, $4)',
            [customerId, amountInCents, status, date]
        );
    } catch (error) {
        console.error('发票创建失败:', error);
        throw new Error('发票创建失败');
    }

    revalidatePath('/dashboard/invoices');
    redirect('/dashboard/invoices');
}

这样就可以将我们的数据新增存储到数据库,并且可以返回到发票列表的目录下。

  1. revalidatePath('/dashboard/invoices'):

    • 这个函数用于重新验证特定路径的缓存。

    • Next.js 使用缓存来提高性能,特别是对于静态生成(SSG)和增量静态再生(ISR)的页面。

    • 当您创建新的发票时,'/dashboard/invoices' 页面的内容可能已经被缓存。

    • 调用 revalidatePath告诉Next.js这个路径的数据已经改变,需要重新生成页面内容。

    • 这确保了用户在重定向到发票列表页面时能看到最新的数据。

  2. redirect('/dashboard/invoices'):

    • 这个函数用于将用户重定向到指定的路径。

    • 在创建发票成功后,我们希望用户看到更新后的发票列表。

以上内容为分页的详细技术实现步骤,如果你想看更多内容或者能够看到技术更新的内容,请百度搜索:曲速引擎 warp drive csdn 在首页找到我的地址访问即可,一线更新内容将会在我的个人博客上面更新,谢谢大家。

更详细内容查看

独立博客 https://www.dataeast.cn/
CSDN博客 https://blog.csdn.net/siberiaWarpDrive
B站视频空间 https://space.bilibili.com/25871614?spm_id_from=333.1007.0.0
关注 “曲速引擎 Warp Drive” 微信公众号


评论