乐趣区

关于前端:form元素是React的未来

大家好,我卡颂。

请思考一个问题:如果有一个 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 元素继续布局。

退出移动版