如果想看专栏的方式可以点击进入Next图册目实践
通过之前的分享,我们已经知道Form表单提交可以在app/api/route.ts
使用handle的方式进行处理。
但其实Next.js13 App Router中提供了一种使用服务器操作处理表单提交和数据更改的强大方法。
服务器操作的工作原理
使用服务器操作,无需手动创建 API 终结点。相反,您可以定义可以直接从组件调用的异步服务器函数。
服务器操作可以在服务器组件中定义,也可以从客户端组件调用。在服务器组件中定义操作允许表单在没有 JavaScript 的情况下运行,从而提供渐进式增强。
简单点来说你可以在use client中直接调用服务端的方法,它可以区分你是服务端方法还是客户端方法!是不突然就感觉很逆天了?
要使用这个特性我们首先需要在next.config.js
文件中启动服务器的操作
java
module.exports = {
experimental: {
serverActions: true,
},
}
要点需知:
- 从服务端组件调用服务器操作的表单可以在没有 JavaScript (浏览器客户端) 的情况下运行。
- 如果 JavaScript 尚未加载,则从客户端组件调用服务器操作的表单将对提交进行排队,从而优先考虑客户端冻结。(客户出现UI线程阻塞)
- 服务器操作继承它们所用页面或布局的运行时。
- 现在的版本如果路由使用
serverActions
,必须要动态呈现。
serverActions
在操作的过程中,是不会整个页面提交的。Next.js内部回知道你想返回什么内容。具体内容可以细看Form中的错误例子。
如何使用?
要serverActions
,请在服务端组件中定义serverActions
。操作可以与函数内第一行定义,也可以在文件顶部具有 use server
指令的单独文件中定义。
javascript
export default function Page() {
async function create(formData: FormData) {
'use server'
// mutate data
// revalidate cache
}
// 这里的action不在写 url地址 可以直接填写方法
return <form action={create}>...</form>
}
当然你也可以写出这种方式
javascript
// app/actions.ts
'use server'
export default async function create(formData: FormData) {
// mutate data
// revalidate cache
}
// app/page.tsx
import create from '@/app/actions'
export default function Page() {
// 这里的action不在写 url地址 可以直接填写方法
return <form action={create}>...</form>
}
表单校验
对于一个web应用开发来说,From组件的数据校验是必不可少的。我们建议使用 HTML 验证,就像 required 和 进行 type="email" 基本表单验证一样。
对于更高级的服务器端验证,梦兽编程这里使用zod进行表单的校验,相比于route.ts的handle 可以少写一步代码。
ini
req.fromData().then(values=>{})
javascript
import { z } from 'zod'
const schema = z.object({
// ...
})
export default async function submit(formData: FormData) {
const parsed = schema.parse({
id: formData.get('id'),
})
// ...
}
提交的状态怎么做呢?
这里需要用到react-dom
的一些api,
javascript
'use client'
import { experimental_useFormStatus as useFormStatus } from 'react-dom'
function SubmitButton() {
const { pending } = useFormStatus()
return (
<button disabled={pending}>{pending ? 'Submitting...' : 'Submit'}</button>
)
}
From的错误状态处理
javascript
'use server'
export async function create(formData: FormData) {
try {
await createItem(formData.get('item'))
revalidatePath('/')
return { message: 'Success!' }
} catch (e) {
return { message: 'There was an error.' }
}
}
我们依然可以返回json格式,回顾上面所说,我们在客户端组件中就可以直接获取操作,前方高能的前后端RPC通信
javascript
'use client'
import { create } from './actions'
import { useState } from 'react'
export default function Page() {
const [message, setMessage] = useState<string>('')
async function onCreate(formData: FormData) {
const res = await create(formData)
//是不是很方便呢?这不比TRPC方便?
setMessage(res.message)
}
return (
<form action={onCreate}>
<input type="text" name="item" />
<button type="submit">Add</button>
<p>{message}</p>
</form>
)
}
其他
其他关于 headers cookie 等操作和Node.js,Next.js中route的handle操作类似。也是web常用技巧,这里就不展开说了,感兴趣的可以回去观看之前的内容。
感谢你的阅读,期待在下一篇文章中再次见到你!
我的B站视频号更多视频动态。
本文使用 markdown.com.cn 排版