异步数据修改和处理是现代网络应用程序的必要任务。你可能希望在服务器上执行一个独立的异步函数来执行诸如将数据保存到数据存储、发送电子邮件、下载PDF、处理图像等任务。
Next.js为我们提供了服务器动作
,这是一种在服务器上执行的异步函数。我们可以使用服务器动作在服务器上进行数据修改,但服务器动作可以从服务器和客户端组件中调用。
服务器动作是处理表单提交的好方法,当表单数据提交时执行操作。在这篇文章中,我们将探讨Next.js服务器动作中处理附加参数的实际用例。
如果你对学习Next.js服务器动作的设计模式和项目构建感兴趣,我为你准备了一个速成课程,你可以在这里找到这里。
此外,这篇文章也作为视频教程在此处可用:
目录
为什么需要传递额外参数?
当我们在表单提交时执行服务器动作,服务器动作会自动获取表单数据。例如,看看下面的表单:
<form className="p-4 flex" action={updateUser}>
<Input className="w-1/2 mx-2" type="text" name="name" />
<Button type="submit">Update User Name</Button>
</form>
在这里,当表单提交时,我们执行一个名为updateUser
的服务器动作。updateUser
函数将接收提交的表单数据作为参数,可以用来提取表单字段的值。
正如下面代码片段所示,updateUser
函数接收一个formData
作为参数,我们可以从中提取name
字段的值。
"use server"
export async function updateUser(formData) {
const name = formData.get('name');
console.log(name);
}
虽然这个模式覆盖了大多数基本用例,但您可能需要以编程方式向服务器动作传递额外参数。这些参数不是表单或表单数据或用户输入数据的一部分。它们是您以编程方式传递给服务器动作的值。
为了理解这一点,请查看下面的服务器动作代码片段。这是我们之前看到过的同一个服务器动作,但我们传递了一个额外的userId
参数,与常规的formData
参数一起传递。
"use server"
export async function updateUser(userId, formData) {
const name = formData.get('name');
console.log(userId);
console.log(name);
}
userId
的值是应用程序内部的某些内容 – 您不会要求用户将该值作为表单提交的一部分提交。相反,您可能需要以编程方式将该值传递给您的服务器动作以执行进一步的计算。
对,那就是我们谈论的用例。既然我们理解了为什么需要它,让我们了解如何实现它。但首先,让我们为表单创建一个服务器动作。
带有服务器动作的表单
在您的Next.js应用程序的app
目录下创建一个名为actions
的目录。现在在actions
文件夹下创建一个名为user.js
的文件,并使用以下代码:
"use server"
export async function updateUser(formData) {
const name = formData.get('name');
console.log(name);
// 随便对name做任何事情,存入数据库,创建发票,等等!
}
这就是您在Next.js中创建服务器函数的方法。文件顶部必须有一个”use server”
指令,以告诉Next.js这是一个特殊的文件,其中包含一个或多个在服务器上执行的异步函数。
然后我们有一个服务器动作(异步函数)updateUser
,它以formData
作为参数。在函数定义内部,我们提取出name
值并在控制台上打印它。
现在让我们把这个服务器动作附加到一个表单上。为此,在项目根目录下创建一个名为components
的文件夹。创建一个名为user-form.jsx
的文件,代码如下:
import { Input } from "./ui/input"
import { Button } from "./ui/button"
import { updateUser } from "@/app/actions/user"
const UserForm = () => {
return(
<form className="p-4 flex" action={updateUser}>
<Input className="w-1/2 mx-2" type="text" name="name" />
<Button type="submit">Update User Name</Button>
</form>
)
}
export default UserForm;
这是一个简单的React组件,包含一个表单。该表单有一个名为name
的输入文本字段和一个提交表单的按钮。表单有一个action
属性,其值为服务器动作updateUser
。现在,当表单提交时带有name
值,服务器动作将作为表单数据的一部分接收,如我们上面所讨论的。
让我们来测试一下。为此,我们将创建一个Next.js路由来使用UserForm
组件。在app
目录下创建一个名为extra-args
的文件夹。现在,在app/extra-args
目录下创建一个名为page.js
的文件,代码如下:
import UserForm from "@/components/user-form";
const ExtraArgsDemo = () => {
return (
<UserForm />
)
}
export default ExtraArgsDemo;
这是一个简单的React组件,我们导入UserForm
组件并在JSX中使用它。现在运行本地服务器并访问此路由localhost:3000/extra-args
。您应该看到带有文本字段和按钮的表单。
在文本字段中输入一些文本并点击按钮。
现在,您将看到输入的文本已经打印在服务器控制台上。为什么是在服务器控制台而不是在浏览器控制台呢?这是因为服务器上的操作在服务器上执行,而不是在客户端浏览器上。
所以,通过这一点,我们现在已经建立了一个这样的数据流动:
页面 => 表单 => 服务器动作
页面有一个表单。当表单提交时,它会执行一个服务器动作。服务器动作在服务器控制台上打印表单数据。
现在让我们增强这些部分,以向服务器动作传递附加参数。
如何传递附加参数
让我们将一个名为UserForm
的组件从页面中传递一个属性。我们将传递一个带有值的userId
,假装我们正在以编程方式将这个userId传递到我们的表单和从那里到服务器动作。
import UserForm from "@/components/user-form";
const ExtraArgsDemo = () => {
return (
<UserForm userId={"1234"} />
)
}
export default ExtraArgsDemo;
在UserForm
组件中,我们接受userId
属性。现在,我们需要做一些特别的事情,以便将这个userId传递到updateUser
服务器动作。
JavaScript有一个神奇的方法叫做bind()
,它可以帮助我们创建一个部分应用函数
。通过这个部分应用函数,您可以从另一个函数的预设参数创建一个函数。
在我们的情况下,updateUser
函数已经有一个名为formData
的参数。现在我们可以使用bind()
方法将userId
作为附加参数传递给新的函数。
const updatedUserWithId = updateUser.bind(null, userId);
bind()
方法的第一个参数是您要绑定函数的上下文。上下文处理函数与this
关键字值的关联。在我们的情况下,由于我们没有更改它,可以将其保持为null
。之后,我们传递了新的参数userId
。值得注意的是,bind()
方法适用于服务器和客户端组件。
以下是修改后的UserForm
组件(user-form.jsx
文件)。请注意,表单的action属性值现在已修改为新函数updatedUserWithId
。
import { Input } from "./ui/input"
import { Button } from "./ui/button"
import { updateUser } from "@/app/actions/user"
const UserForm = ({userId}) => {
const updatedUserWithId = updateUser.bind(null, userId);
return(
<form className="p-4 flex" action={updatedUserWithId}>
<Input className="w-1/2 mx-2" type="text" name="name" />
<Button type="submit">Update User Name</Button>
</form>
)
}
export default UserForm;
现在,服务器动作将接收userId
值作为一个参数。我们也可以将其打印到控制台上。
"use server"
export async function updateUser(userId, formData) {
const name = formData.get('name');
console.log(userId);
console.log(name);
// 做任何与用户id和姓名相关的操作,保存在数据库中,
// 创建发票,等等!
}
现在,如果您提交带有姓名值的表单:
您将看到userId和姓名值都被记录到服务器控制台上。太棒了!我们已经记录了表单数据的一个值,另一个值则是内部传递给了服务器动作。
因此,我们学会了如何将额外的参数与表单数据一起传递给服务器动作。
那隐藏域呢?
HTML支持隐藏类型的表单字段,以便将客户端数据传递到服务器,而不接受用户的输入。所以这意味着我们可以使用隐藏字段来传递userId
的值,就像这样:
那么为什么我们要用bind()
方法来做这些呢?嗯,因为安全问题。当你使用隐藏字段传递数据时,该值将成为渲染的HTML的一部分,并且不会被编码。所以最好通过编程方式处理它。
资源
暂时就这些。你喜欢阅读这篇文章吗?你学到了新的知识吗?如果是的话,我很想知道内容是否有帮助。让我分享一些你可能需要的其他资源:
此外,您可以通过以下方式与我联系:
-
订阅我的YouTube频道。如果您想学习
React
及其生态系统,例如Next.js
,包括基本概念和项目,我有一个好消息告诉您:您可以在我的YouTube频道的这个播放列表中查看25+个视频教程和15+小时的引人入胜的内容,全部免费。我希望您也会喜欢它们。 -
如果在Twitter上关注我X,或者在LinkedIn上关注我,你不会错过每天的提升技巧剂量。
-
查看并在GitHub上关注我的开源工作。
-
我在我的GreenRoots Blog上定期发布有意义的帖子,你可能会觉得它们也有帮助。
期待不久的将来,我的下一篇文章。在此之前,请照顾好自己,并继续学习。
Source:
https://www.freecodecamp.org/news/how-to-pass-additional-arguments-to-nextjs-server-actions/