大家好,我卡颂。
请思考一个问题:如果有一个 HTML
标签,React
围绕他专门出了 2 个 hook
,那这个标签对React
将来的倒退肯定十分重要,这没故障吧?
这个标签就是 —— form
。
React
围绕 form
新出了如下 2 个hook
:
useOptimistic
useFormStatus
本文会聊聊 React
围绕 form
的布局与倒退。
欢送退出人类高质量前端交换群,带飞
Next.js 的倒退历程
说到 React
将来的倒退,必须从 Next.js
聊起。毕竟,React
团队成员不是退出 Next
团队,就是在退出的路上。
web
开发中波及到前后端交互的局部次要包含:
- 依据后端数据渲染前端页面
- 依据前端用户输出保留数据到后端
Next.js
的倒退次要围绕以上两点开展。
依据后端数据渲染前端页面
后期,Next.js
的主打个性是 SSR
、SSG
。也就是把 依据后端数据渲染前端页面 的过程从前端挪到后端。
这个期间的 Next.js
路由被称为Pages Router
。
工夫来到 Next.js v13
,以RSC
(React Server Component)为外围的App Router
取代 Pages Router
成为默认配置。
很多敌人不相熟 RSC
,认为他是试验个性。实际上,RSC
借由 Next.js
曾经落地了。
一句话了解 RSC
—— 客户端组件(在浏览器渲染的React
组件)能够依据依赖分为两局部:
- 依赖数据源(比方数据库、文件系统)的组件,能够作为
RSC
(服务端组件) - 依赖状态(比方
state
、props
、context
)的组件,能够作为客户端组件
从 依据后端数据渲染前端页面 角度看:
SSR
、SSG
是页面级别的(服务端渲染出现的是整个页面)RSC
是组件级别的(服务端组件申请数据源)
依据前端用户输出保留数据到后端
聊完了 依据后端数据渲染前端页面 ,那么,围绕 依据前端用户输出保留数据到后端 ,Next.js
能做哪些优化?
这就要提到 Next.js
的试验个性 —— Server Action
。
Server Action
依据前端用户输出保留数据到后端 的常见场景是 表单提交 ,通常咱们会在form
的obSubmit
事件中做后续解决:
function Form() {function submit() {
// ... 解决 formData 的逻辑
// ... 发送申请的逻辑
}
return (<form onSubmit={submit}>
<input type="text"/>
<input type="text"/>
</form>
)
}
以上代码有什么可改良的中央呢?
从用户体验的角度看,如果前端禁用了 JS
,那么React
不能运行,上述交互生效。如果在禁用 JS
的状况下也能提交表单就好了。
从开发体验的角度看,submit
办法会发动申请,后端再依据申请携带的 formData
操作数据库,比拟繁琐。如果在 submit
办法内能间接操作数据库就好了。
Server Action
个性就是为了实现以上 2 个指标。
首先来看第一个指标。
指标 1
HTML
原生的 form
元素有个 action
属性,能够接管一个 url
。当提交表单(比方点击type
为submit
的按钮)后 formData
会提交给该url
。
<form action="/action_page.php" method="get">
<label for="fname">First name:</label>
<input type="text" id="fname" name="fname"><br><br>
<label for="lname">Last name:</label>
<input type="text" id="lname" name="lname"><br><br>
<input type="submit" value="Submit">
</form>
因为 提交表单 的行为是 HTML
原生反对的,所以在禁用 JS
的状况下也能执行。
这就是禁用 JS
也能提交表单的实践根底。
指标 2
React
扩大了 form
的action
属性,让他除了反对url
,还能反对回调函数,比方:
function App() {function submit(data) {// ...}
return (<form action={submit}>
<! -- 省略 -->
</form>
);
如果这个回调函数内是前端执行的逻辑,则被称为client action
,比方上面这样:
async function submit(data) {await const res = saveData(data);
// ...
}
如果这个函数内是后端执行的逻辑,则被称为server action
,比方上面这样:
"use server"
async function submit(data) {const userID = cookies().get("userID")?.value;
await db.users.update(userID, data);
// ...
}
"use server"
标记代表这是个server action
。
如果是server action
,那么发动的申请类型是multipart/form-data
(即表单提交):
响应类型则是RSC 协定
:
也就是说,有了 server action
,开发者能够间接在form
的action
属性(或者 button
的formAction
属性等其余几种属性)内书写后端逻辑,并且在浏览器禁用 JS
的状况下这些逻辑也能执行。
2 个新 hook
为了更好的服务 server action
,React
团队新出了 2 个 hook
用于进步 form
场景下的用户体验:
useOptimistic
useFormStatus
以后,这 2 个 hook
的介绍只能在 Next.js 文档(而不是 React
文档)中看到。
useOptimistic
次要用来优化 提交数据 的用户体验。
比方,在 点赞 的场景,通常逻辑是:
- 点击点赞按钮
- 发动点赞申请
- 点赞胜利,前端显示点赞成果
但为了用户体验的晦涩,前端通常会把逻辑做成:
- 点击点赞按钮
- 前端显示点赞成果(同时发动点赞申请)
- 依据申请后果,如果点赞胜利则不做解决,如果点赞失败则重置按钮
useOptimistic
的实质就是在状态层面实现上述成果。
useFormStatus
则用于在表单提交过程中显示 pending
状态:
function ButtonDisabledWhilePending({action, children}) {const {pending} = useFormStatus();
return (<button disabled={pending} formAction={action}>
{children}
</button>
);
}
有同学可能会纳闷:useFormStatus
没有传参,他怎么晓得对应哪个form
?
实际上,为了实现 useFormStatus
,React
在源码内为所有 HostComponent
(即原生HTML
元素对应组件,比方<div/>
)定制了一个context
。
当某个 form
触发表单提交时,context
的值会被更新为这个 form
的数据。useFormStatus
自身仅仅是useContext(上述 context)
。
总结
能够发现,不论是 useFormStatus
、useOptimistic
还是最近 1~2 年新出的hook
(比方useId
、useMutableSource
),咱们开发者都很少会用到。
因为这些 hook
都是为下层框架(次要是Next.js
)提供的。
React
早已实现他作为前端框架的使命。在他生命的后半程,他将作为下层框架的 操作系统 而存在。
server action
是 Next.js
的将来,Next.js
是 React
的将来。所以,React
的将来会围绕 form
元素继续布局。