React 19 核心新特性全解:Actions(useActionState / useOptimistic)、use() API 与 ref 架构简化是如何协同的?

React 19 围绕 异步数据突变(Actions)状态自动化、一等公民 Promise 读取原语 use() 以及 消除历史样板代码(如 forwardRef) 进行了全面升级。

一、 React 18 手写异步表单 vs React 19 Actions 原语对比

在 React 18 中处理一次表单提交,开发者必须手动维护 isPending、error、optimisticData 三个状态;React 19 将支持 async 函数的过渡更新统称为 Actions,并提供了三大配套 Hook:

React 19 新 API 核心职责与解决的痛点
useActionState(fn, initialState) 自动接管 Action 的 pending 状态、上一次返回值 state 及包裹后的提交函数 formAction,可直接绑定到 <form action={formAction}>
useFormStatus() 在表单内部的深层子组件(如通用 <SubmitButton />)中直接读取外层 <form> 的 { pending, data },无需层层透传 loading Prop
useOptimistic(state, updateFn) 在异步 Action 进行期间立即渲染乐观状态;一旦异步 Action 结束或失败,自动无感回退或对齐真实状态
use(resource) 可在组件渲染期间(甚至支持写在 if 条件分支和循环内部!)直接读取 Promise(配合 <Suspense>)或读取 Context
ref 作为普通 Prop 函数组件直接通过 function MyInput({ placeholder, ref }) 接收 ref,彻底淘汰 React.forwardRef 包装器

二、 React 19 完整代码实战:Actions + 乐观更新 + use()

import { useActionState, useOptimistic, use } from 'react'
import { useFormStatus } from 'react-dom'

// 1. 通用提交按钮:自动感知所属 <form> 的提交状态,无需父组件传 loading
function SubmitButton() {
  const { pending } = useFormStatus()
  return <button type="submit" disabled={pending}>{pending ? '发布中...' : '发表评论'}</button>
}

// 2. 使用 useActionState + useOptimistic 实现零样板代码的乐观评论列表
export function CommentSection({ commentsPromise }: { commentsPromise: Promise<string[]> }) {
  // use() 直接解包父级传入的 Promise(并支持写在条件判断后!)
  const initialComments = use(commentsPromise)

  const [comments, formAction] = useActionState(
    async (prevComments: string[], formData: FormData) => {
      const text = String(formData.get('comment') || '').trim()
      await saveCommentToServer(text) // 真实异步请求
      return [...prevComments, text]
    },
    initialComments
  )

  const [optimisticComments, addOptimistic] = useOptimistic(
    comments,
    (state, newComment: string) => [...state, `${newComment} (发送中...)`]
  )

  return (
    <div>
      <ul>{optimisticComments.map((c, i) => <li key={i}>{c}</li>)}</ul>
      <form
        action={async (formData) => {
          addOptimistic(String(formData.get('comment') || ''))
          await formAction(formData)
        }}
      >
        <input name="comment" required />
        <SubmitButton />
      </form>
    </div>
  )
}

同分类其他题目