Form 元素是 React 的未来 每日速讯
大家好,我卡颂。
请思考一个问题:如果有一个HTML标签,React围绕他专门出了2个hook,那这个标签对React未来的发展一定非常重要,这没毛病吧?
这个标签就是 ——form。
(资料图片仅供参考)
React围绕form新出了如下2个hook:
useOptimisticuseFormStatus本文会聊聊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
的onSubmit
事件中做后续处理:
function Form() { function submit() { // ...处理formData的逻辑 // ...发送请求的逻辑 } return ( )}
以上代码有什么可改进的地方呢?
从用户体验的角度看,如果前端禁用了JS,那么React不能运行,上述交互失效。如果在禁用JS的情况下也能提交表单就好了。
从开发体验的角度看,submit方法会发起请求,后端再根据请求携带的formData操作数据库,比较繁琐。如果在submit方法内能直接操作数据库就好了。
Server Action特性就是为了实现以上2个目标。
首先来看第一个目标。
目标1HTML原生的form元素有个action属性,可以接收一个url。当提交表单(比如点击type为submit的按钮)后formData会提交给该url。
由于「提交表单」的行为是HTML原生支持的,所以在禁用JS的情况下也能执行。
这就是禁用JS也能提交表单的理论基础。
目标2React扩展了form的action属性,让他除了支持url,还能支持回调函数,比如:
function App() { function submit(data) { // ... } return ( );
如果这个回调函数内是前端执行的逻辑,则被称为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场景下的用户体验:
useOptimisticuseFormStatus当前,这2个hook的介绍只能在Next.js文档[1](而不是React文档)中看到。
useOptimistic主要用来优化「提交数据」的用户体验。
比如,在「点赞」的场景,通常逻辑是:
点击点赞按钮发起点赞请求点赞成功,前端显示点赞效果但为了用户体验的流畅,前端通常会把逻辑做成:
点击点赞按钮前端显示点赞效果(同时发起点赞请求)根据请求结果,如果点赞成功则不做处理,如果点赞失败则重置按钮useOptimistic的本质就是在状态层面实现上述效果。
useFormStatus则用于在表单提交过程中显示pending状态:
function ButtonDisabledWhilePending({action, children}) { const {pending} = useFormStatus(); return ( );}
有同学可能会疑惑:useFormStatus没有传参,他怎么知道对应哪个form?
实际上,为了实现useFormStatus,React在源码内为所有HostComponent(即原生HTML元素对应组件,比如
)定制了一个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元素持续布局。
参考资料[1]Next.js文档:https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions#experimental-useoptimistic。