前端框架 精选推荐

React 19 新特性全面解读:Actions、use Hook 与 Server Components 改进

HTMLPAGE 团队
18 分钟阅读

深入解析 React 19 的重要更新,包括 Actions 简化表单处理、use Hook 统一资源读取、以及 Server Components 的成熟化改进

#React 19 #Actions #use Hook #Server Components

React 19 的定位

如果说 React 18 的主题是"并发渲染",那么 React 19 的主题是"开发体验与服务端能力的深化"。

这个版本没有引入革命性的新概念,而是让 React 18 引入的能力更加实用、更加易用。Server Components 从"能用"变成"好用",表单处理从"繁琐"变成"优雅",异步数据获取从"各显神通"变成"统一方案"。

Actions:表单处理的范式变革

传统表单的痛点

React 中处理表单一直是痛点。一个简单的提交表单需要:

  1. 用 useState 管理表单字段
  2. 用 useState 管理 loading 状态
  3. 用 useState 管理错误状态
  4. 写 handleSubmit 函数处理提交
  5. 手动处理成功/失败后的 UI 更新

代码往往变成这样:

function ContactForm() {
  const [name, setName] = useState('')
  const [email, setEmail] = useState('')
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState(null)
  const [success, setSuccess] = useState(false)

  async function handleSubmit(e) {
    e.preventDefault()
    setLoading(true)
    setError(null)
    try {
      await submitForm({ name, email })
      setSuccess(true)
    } catch (err) {
      setError(err.message)
    } finally {
      setLoading(false)
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      {/* ... */}
    </form>
  )
}

这还是最简单的情况,没考虑验证、重复提交防护、乐观更新...

Actions 的解法

React 19 的 Actions 让表单处理回归简洁:

async function submitAction(formData) {
  'use server' // 在服务端执行
  const name = formData.get('name')
  const email = formData.get('email')
  await saveToDatabase({ name, email })
}

function ContactForm() {
  return (
    <form action={submitAction}>
      <input name="name" />
      <input name="email" />
      <button type="submit">提交</button>
    </form>
  )
}

不需要 useState,不需要 handleSubmit,不需要手动管理 loading——框架帮你处理。

useFormStatus:获取表单状态

提交按钮需要显示 loading 状态?用 useFormStatus

function SubmitButton() {
  const { pending } = useFormStatus()
  return (
    <button disabled={pending}>
      {pending ? '提交中...' : '提交'}
    </button>
  )
}

这个 Hook 只能在 <form> 内部的组件中使用,自动获取最近表单的状态。

useActionState:完整的状态管理

需要更多控制?useActionState 提供完整的状态管理:

async function updateName(previousState, formData) {
  const name = formData.get('name')
  if (!name) {
    return { error: '名称不能为空' }
  }
  await updateUser({ name })
  return { success: true }
}

function UpdateNameForm() {
  const [state, formAction, isPending] = useActionState(updateName, null)

  return (
    <form action={formAction}>
      <input name="name" />
      <button disabled={isPending}>更新</button>
      {state?.error && <p className="error">{state.error}</p>}
      {state?.success && <p className="success">更新成功</p>}
    </form>
  )
}

useOptimistic:乐观更新

用户点击后立即反馈,不等服务端响应:

function TodoItem({ todo, updateAction }) {
  const [optimisticTodo, setOptimisticTodo] = useOptimistic(todo)

  async function handleToggle() {
    setOptimisticTodo({ ...todo, done: !todo.done })
    await updateAction(todo.id, !todo.done)
  }

  return (
    <div>
      <input
        type="checkbox"
        checked={optimisticTodo.done}
        onChange={handleToggle}
      />
      {optimisticTodo.title}
    </div>
  )
}

点击后立即切换状态,如果服务端失败再回滚。用户感知到的响应速度极快。

use Hook:统一的资源读取

Promise 直接读取

之前读取异步数据需要 useEffect + useState 的组合。React 19 引入 use Hook,可以直接在组件中读取 Promise:

function UserProfile({ userPromise }) {
  const user = use(userPromise)
  return <h1>{user.name}</h1>
}

注意这不是在组件内发起请求,而是读取已存在的 Promise。请求应该在父组件或数据层发起。

Context 读取

use 也可以读取 Context,而且支持条件调用:

function Sidebar({ showSettings }) {
  if (showSettings) {
    const settings = use(SettingsContext) // 条件调用
    return <SettingsPanel settings={settings} />
  }
  return <DefaultSidebar />
}

传统的 useContext 不能在条件语句中调用,use 打破了这个限制。

与 Suspense 配合

use 读取 Promise 时,会触发 Suspense:

function App() {
  const userPromise = fetchUser(userId)

  return (
    <Suspense fallback={<Loading />}>
      <UserProfile userPromise={userPromise} />
    </Suspense>
  )
}

在数据加载完成前显示 Loading,完成后自动渲染 UserProfile。

ref 改进

ref 作为普通 prop

之前传递 ref 需要 forwardRef:

// React 18
const Input = forwardRef((props, ref) => (
  <input ref={ref} {...props} />
))

React 19 中,ref 可以直接作为 prop:

// React 19
function Input({ ref, ...props }) {
  return <input ref={ref} {...props} />
}

forwardRef 仍然可用,但不再是唯一选择。

ref 回调清理函数

ref 回调现在支持返回清理函数:

<input
  ref={(element) => {
    // 元素挂载时执行
    const instance = initializeLibrary(element)

    return () => {
      // 元素卸载时执行
      instance.destroy()
    }
  }}
/>

之前需要额外的 useEffect 来处理清理,现在一个回调搞定。

Server Components 的成熟

Directives 稳定

'use client''use server' 指令正式稳定:

'use client' // 标记客户端组件边界

function InteractiveButton() {
  const [count, setCount] = useState(0)
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>
}
'use server' // 标记服务端 Action

async function saveData(formData) {
  await db.insert(formData)
}

错误处理改进

Server Components 的错误现在能被错误边界正确捕获:

<ErrorBoundary fallback={<ErrorMessage />}>
  <ServerComponent />
</ErrorBoundary>

之前 Server Components 的错误可能导致整个页面崩溃,现在可以优雅降级。

流式传输优化

Server Components 的流式传输更加稳定:

  • Suspense 边界的处理更合理
  • 网络中断后的恢复更可靠
  • 错误状态的传播更清晰

文档 Metadata 支持

原生 title 和 meta

React 19 内置了对文档元数据的支持:

function BlogPost({ post }) {
  return (
    <>
      <title>{post.title}</title>
      <meta name="description" content={post.excerpt} />
      <meta name="author" content={post.author} />
      <article>{post.content}</article>
    </>
  )
}

这些标签会自动提升到 <head> 中,无需 react-helmet 等第三方库。

样式表和脚本的加载也有了统一管理:

function MyComponent() {
  return (
    <>
      <link rel="stylesheet" href="/styles.css" precedence="default" />
      <script src="/analytics.js" async />
      <div>内容</div>
    </>
  )
}

precedence 属性控制样式表的优先级,框架会自动去重和排序。

开发体验提升

改进的错误提示

错误信息更加清晰:

  • 组件栈追踪更准确
  • 水合错误定位到具体元素
  • 废弃 API 有明确的迁移指引

Strict Mode 增强

开发模式下的检查更严格:

  • 检测更多的副作用问题
  • 模拟组件的卸载重载
  • 提前发现并发模式下的问题

迁移指南

破坏性变更

React 19 的破坏性变更主要是清理历史包袱:

已废弃的 API 移除

  • propTypes 运行时检查移除(建议用 TypeScript)
  • defaultProps 在函数组件中废弃(用默认参数)
  • 字符串 ref 移除(早在多年前就废弃了)

行为变更

  • useRef 必须传初始值
  • useDeferredValue 第二个参数改为选项对象
  • 部分类型定义调整

渐进式升级

  1. 先升级到 React 18.3:这是一个特殊版本,会警告将在 19 中移除的 API
  2. 修复所有警告:根据控制台提示修改代码
  3. 升级到 React 19:确保测试通过
  4. 采用新特性:在新代码中使用 Actions、use 等

常见问题

Q:需要重写所有表单吗? A:不需要。传统的 useState + handleSubmit 仍然有效,Actions 是额外选项。

Q:use Hook 会取代 useEffect 获取数据吗? A:不会。use 是读取已存在的资源,发起请求仍然需要其他方式(Server Components、数据加载库等)。

Q:Server Components 必须用吗? A:看框架。在 Next.js App Router 中是默认的,纯客户端 React 应用不涉及。

总结

React 19 的核心价值:

特性解决的问题
Actions简化表单状态管理
useFormStatus无痛获取表单状态
useActionState细粒度的 Action 控制
useOptimistic乐观更新开箱即用
use Hook统一的资源读取方式
ref 改进减少 forwardRef 样板
Metadata 支持原生文档元数据管理

React 19 体现了框架成熟期的特征:不追求颠覆性创新,而是让已有概念更易用、更实用。对于日常开发,这些改进的累积效应相当可观。


相关文章推荐: