返回首页 React 19

React 19 新特性全解析:下一代前端框架

React 19 带来了多年来最重要的更新,包括 Server Components、Actions、新的 Hook 以及完全重写的渲染引擎。本文将全面解析这些新特性,帮助你快速掌握 React 19 的强大功能。


React 19 概览

React 19 是一个重要的里程碑版本,引入了许多期待已久的功能:

升级要求

{
  "dependencies": {
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  },
  "devDependencies": {
    "@types/react": "^19.0.0",
    "@types/react-dom": "^19.0.0"
  }
}

Server Components

Server Components (RSC) 是 React 19 最重磅的功能,它允许组件在服务器上渲染,只将必要的 HTML 发送到客户端。

基本用法

// app/page.js (Server Component)
async function BlogPage() {
  const posts = await db.posts.findMany()

  return (
    <div>
      <h1>Blog</h1>
      {posts.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.content}</p>
        </article>
      ))}
    </div>
  )
}

Server vs Client Components

特性 Server Components Client Components
运行位置 服务器 浏览器
可以访问后端
可以交互
增加包大小

标记 Client Component

// ✅ Client Component - 可以有状态和交互
'use client'

import { useState } from 'react'

export function LikeButton() {
  const [liked, setLiked] = useState(false)

  return (
    <button onClick={() => setLiked(!liked)}>
      {liked ? '❤️' : '🤍'}
    </button>
  )
}

混用 Server 和 Client Components

// Server Component
import { LikeButton } from './like-button'

async function Post({ id }) {
  const post = await db.post.findUnique({ where: { id } })

  return (
    <article>
      <h2>{post.title}</h2>
      <p>{post.content}</p>
      <!-- Client Component 仍然可以嵌套 -->
      <LikeButton postId={post.id} />
    </article>
  )
}

Actions 与表单处理

React 19 引入了 Actions 的概念,简化了表单提交和异步操作的处理。

基本用法

// 定义 Action
async function updateName(formData) {
  const name = formData.get('name')
  await db.user.update({ name })
}

// 在表单中使用
function NameForm() {
  return (
    <form action={updateName}>
      <input type="text" name="name" />
      <button type="submit">Update</button>
    </form>
  )
}

useActionState Hook

import { useActionState } from 'react'

function ChangeNameForm() {
  const [state, formAction, isPending] = useActionState(
    async (prevState, formData) => {
      const name = formData.get('name')
      await updateName(name)
      return { success: true, error: null }
    },
    { success: false, error: null }
  )

  return (
    <form action={formAction}>
      <input type="text" name="name" />
      <button type="submit" disabled={isPending}>
        {isPending ? 'Updating...' : 'Update'}
      </button>
      {state.success && <p>Name updated!</p>}
    </form>
  )
}

useFormStatus Hook

import { useFormStatus } from 'react'

function SubmitButton() {
  const { pending } = useFormStatus()

  return (
    <button type="submit" disabled={pending}>
      {pending ? 'Submitting...' : 'Submit'}
    </button>
  )
}

function Form() {
  async function submit(formData) {
    // 提交逻辑
  }

  return (
    <form action={submit}>
      <SubmitButton />
    </form>
  )
}

useOptimistic Hook

用于在等待服务器响应时立即更新 UI,提供更流畅的用户体验。

import { useOptimistic } from 'react'

function LikeButton({ postId, initialLiked }) {
  const [liked, setLiked] = useState(initialLiked)

  const optimisticLiked = useOptimistic(liked, {
    pending: true,
    action: async (current) => {
      // 乐观更新:立即切换状态
      const newValue = !current
      // 后台执行服务器更新
      await toggleLike(postId, newValue)
      return newValue
    }
  })

  return (
    <button
      onClick={() => optimisticLiked.action(optimisticLiked.value)}
      disabled={optimisticLiked.pending}
    >
      {optimisticLiked.value ? '❤️' : '🤍'}
      {optimisticLiked.pending && ' (updating...)'}
    </button>
  )
}

实际应用示例

function TodoList() {
  const [todos, setTodos] = useState([
    { id: 1, text: 'Learn React 19', done: false }
  ])

  const [optimisticTodos, addOptimistic] = useOptimistic(
    todos,
    (state, newTodo) => [...state, { ...newTodo, pending: true }]
  )

  async function addTodo(formData) {
    const text = formData.get('text')
    const newTodo = { id: Date.now(), text, done: false }

    // 立即显示
    addOptimistic(newTodo)

    // 服务器更新
    await db.todos.create({ data: newTodo })

    // 更新真实状态
    setTodos(prev => [...prev, newTodo])
  }

  return (
    <form action={addTodo}>
      <input type="text" name="text" />
      <button type="submit">Add</button>

      <ul>
        {optimisticTodos.map(todo => (
          <li key={todo.id}>
            {todo.text}
            {todo.pending && ' (saving...)'}
          </li>
        ))}
      </ul>
    </form>
  )
}

增强的 useTransition

React 19 改进了 useTransition,使其更强大且易于使用。

import { useTransition } from 'react'

function SearchResults() {
  const [query, setQuery] = useState('')
  const [results, setResults] = useState([])
  const [isPending, startTransition] = useTransition()

  function handleChange(e) {
    const value = e.target.value

    // 立即更新输入框
    setQuery(value)

    // 标记搜索为过渡更新
    startTransition(async () => {
      const results = await search(value)
      setResults(results)
    })
  }

  return (
    <div>
      <input value={query} onChange={handleChange} />
      {isPending ? <p>Searching...</p> : <ResultList results={results} />}
    </div>
  )
}

其他新 Hook

use API - 读取 Context

import { use } from 'react'

// 从 context 中读取值
const theme = use(ThemeContext)

// 从 promise 中读取值
const data = use(fetchData())

useId - 稳定的唯一 ID

import { useId } from 'react'

function PasswordFields() {
  const id = useId()

  return (
    <>
      <label htmlFor={`${id}-password`}>Password</label>
      <input id={`${id}-password`} type="password" />

      <label htmlFor={`${id}-confirm`}>Confirm</label>
      <input id={`${id}-confirm`} type="password" />
    </>
  )
}

useSyncExternalStore - 订阅外部 Store

import { useSyncExternalStore } from 'react'

function useStore(store, selector) {
  return useSyncExternalStore(
    store.subscribe,
    () => selector(store.getState()),
    () => selector(store.getInitialState())
  )
}

// 使用
function TodoList() {
  const todos = useStore(todoStore, state => state.todos)
  return <ul>{todos.map(...)}</ul>
}

改进的 Suspense

React 19 改进了 Suspense 的边界处理和错误恢复。

import { Suspense } from 'react'

function BlogPage() {
  return (
    <Suspense fallback={<Spinner />}>
      <BlogPosts />
    </Suspense>
  )
}

async function BlogPosts() {
  const posts = await fetchPosts()
  return (
    <div>
      {posts.map(post => (
        <Suspense key={post.id} fallback={<PostSkeleton />}>
          <BlogPost id={post.id} />
        </Suspense>
      ))}
    </div>
  )
}

Suspense with Error Boundary

import { ErrorBoundary } from 'react-error-boundary'

function App() {
  return (
    <ErrorBoundary
      fallback={
        <div>
          <h2>Something went wrong</h2>
          <button onClick={() => window.location.reload()}>
            Retry
          </button>
        </div>
      }
    >
      <Suspense fallback={<Spinner />}>
        <BlogPage />
      </Suspense>
    </ErrorBoundary>
  )
}

迁移指南

1. 升级依赖

npm install react@19 react-dom@19
npm install -D @types/react@19 @types/react-dom@19

2. 更新 JSX Transform

// 移除 React 导入(不再需要)
// ❌ 旧写法
import React from 'react'
export default function App() {
  return <div />
}

// ✅ 新写法
export default function App() {
  return <div />
}

3. 更新渲染 API

// ❌ ReactDOM.render 已废弃
import ReactDOM from 'react-dom'
ReactDOM.render(<App />, document.getElementById('root'))

// ✅ 使用 createRoot
import { createRoot } from 'react-dom/client'
const root = createRoot(document.getElementById('root'))
root.render(<App />)

4. 过滤掉的 PropTypes

// React 19 不再在运行时检查 PropTypes
// 考虑使用 TypeScript 替代
interface ButtonProps {
  label: string
  onClick: () => void
}

function Button({ label, onClick }: ButtonProps) {
  return <button onClick={onClick}>{label}</button>
}

总结

React 19 是一次重大更新,带来了许多强大的新功能。Server Components 让我们能够构建更快速的应用,Actions 简化了表单处理,新的 Hook 提供了更好的用户体验。

关键要点

学习路径

  1. 先掌握 Server Components 的概念
  2. 学习 Actions 和相关 Hook
  3. 理解 useOptimistic 的使用场景
  4. 实践 Suspense 边界处理
  5. 启用 React Compiler 并验证优化效果