大家好,我卡颂。

请思考一个问题:如果有一个HTML标签,React围绕他专门出了2个hook,那这个标签对React将来的倒退肯定十分重要,这没故障吧?

这个标签就是 —— form

React围绕form新出了如下2个hook

  • useOptimistic
  • useFormStatus

本文会聊聊React围绕form的布局与倒退。

欢送退出人类高质量前端交换群,带飞

Next.js的倒退历程

说到React将来的倒退,必须从Next.js聊起。毕竟,React团队成员不是退出Next团队,就是在退出的路上。

web开发中波及到前后端交互的局部次要包含:

  1. 依据后端数据渲染前端页面
  2. 依据前端用户输出保留数据到后端

Next.js的倒退次要围绕以上两点开展。

依据后端数据渲染前端页面

后期,Next.js的主打个性是SSRSSG。也就是把依据后端数据渲染前端页面的过程从前端挪到后端。

这个期间的Next.js路由被称为Pages Router

工夫来到Next.js v13,以RSC(React Server Component)为外围的App Router取代Pages Router成为默认配置。

很多敌人不相熟RSC,认为他是试验个性。实际上,RSC借由Next.js曾经落地了。

一句话了解RSC —— 客户端组件(在浏览器渲染的React组件)能够依据依赖分为两局部:

  • 依赖数据源(比方数据库、文件系统)的组件,能够作为RSC(服务端组件)
  • 依赖状态(比方statepropscontext)的组件,能够作为客户端组件

依据后端数据渲染前端页面角度看:

  • SSRSSG是页面级别的(服务端渲染出现的是整个页面)
  • RSC是组件级别的(服务端组件申请数据源)

依据前端用户输出保留数据到后端

聊完了依据后端数据渲染前端页面,那么,围绕依据前端用户输出保留数据到后端Next.js能做哪些优化?

这就要提到Next.js的试验个性 —— Server Action

Server Action

依据前端用户输出保留数据到后端的常见场景是表单提交,通常咱们会在formobSubmit事件中做后续解决:

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。当提交表单(比方点击typesubmit的按钮)后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扩大了formaction属性,让他除了反对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,开发者能够间接在formaction属性(或者buttonformAction属性等其余几种属性)内书写后端逻辑,并且在浏览器禁用JS的状况下这些逻辑也能执行。

2个新hook

为了更好的服务server actionReact团队新出了2个hook用于进步form场景下的用户体验:

  • useOptimistic
  • useFormStatus

以后,这2个hook的介绍只能在Next.js文档(而不是React文档)中看到。

useOptimistic次要用来优化提交数据的用户体验。

比方,在点赞的场景,通常逻辑是:

  1. 点击点赞按钮
  2. 发动点赞申请
  3. 点赞胜利,前端显示点赞成果

但为了用户体验的晦涩,前端通常会把逻辑做成:

  1. 点击点赞按钮
  2. 前端显示点赞成果(同时发动点赞申请)
  3. 依据申请后果,如果点赞胜利则不做解决,如果点赞失败则重置按钮

useOptimistic的实质就是在状态层面实现上述成果。

useFormStatus则用于在表单提交过程中显示pending状态:

function ButtonDisabledWhilePending({action, children}) {  const {pending} = useFormStatus();  return (    <button disabled={pending} formAction={action}>      {children}    </button>  );}

有同学可能会纳闷:useFormStatus没有传参,他怎么晓得对应哪个form

实际上,为了实现useFormStatusReact在源码内为所有HostComponent(即原生HTML元素对应组件,比方<div/>)定制了一个context

当某个form触发表单提交时,context的值会被更新为这个form的数据。useFormStatus自身仅仅是useContext(上述context)

总结

能够发现,不论是useFormStatususeOptimistic还是最近1~2年新出的hook(比方useIduseMutableSource),咱们开发者都很少会用到。

因为这些hook都是为下层框架(次要是Next.js)提供的。

React早已实现他作为前端框架的使命。在他生命的后半程,他将作为下层框架的操作系统而存在。

server actionNext.js的将来,Next.jsReact的将来。所以,React的将来会围绕form元素继续布局。