React 19 使用文档(基于 React 19.1)

本文档为 React 19.1 的全面使用指南,涵盖核心功能、新特性、TypeScript 集成及最佳实践。每个知识点都附带详细代码示例,适用于初学者和高级开发者。React 19 引入了多项突破性特性,如 React 编译器、Server Components、Server Actions 和新 Hooks,旨在简化开发、提升性能和优化用户体验。本文档基于官方文档和其他可靠资源(如 React Conf 2024 和 freeCodeCamp)编写。

1. 安装与配置

1.1 安装 React 19

React 19 可通过 npm 安装,推荐在项目中局部安装以确保版本一致性。

npm install react@19.1 react-dom@19.1

TypeScript 用户:确保安装最新类型定义:

npm install --save-dev @types/react@19.0 @types/react-dom@19.0

1.2 配置项目

React 19 要求使用新的 JSX 转换,推荐与 Vite 或 Next.js 等现代构建工具配合。以下是一个 Vite 项目的基本配置:

vite.config.ts

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  build: {
    rollupOptions: {
      output: {
        manualChunks(id) {
          if (id.includes("node_modules")) {
            return "vendor";
          }
        },
      },
    },
  },
});

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "jsx": "react-jsx",
    "moduleResolution": "node",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "baseUrl": "src",
    "paths": {
      "@components/*": ["components/*"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

说明

  • "jsx": "react-jsx" 启用新的 JSX 转换,取代 React.createElement
  • "strict": true 确保类型安全。
  • paths 配置模块别名,简化导入。

2. 核心概念

2.1 组件(Components)

React 19 支持函数组件和类组件,但推荐使用函数组件与 Hooks。

示例:函数组件

import React from "react";

interface Props {
  name: string;
}

const Greeting: React.FC<Props> = ({ name }) => {
  return <h1>Hello, {name}!</h1>;
};

export default Greeting;

使用

import Greeting from "@components/Greeting";

const App: React.FC = () => {
  return <Greeting name="Alice" />;
};

2.2 Props 与 State

Props 用于父子组件通信,State 用于管理组件内部状态。

示例:State 管理

import React, { useState } from "react";

const Counter: React.FC = () => {
  const [count, setCount] = useState<number>(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
};

最佳实践

  • 使用 TypeScript 定义 Props 和 State 类型。
  • 避免过多的 State,优先使用派生状态。
  • 对于复杂状态管理,考虑 useReducer 或 Zustand。

3. React 19 新特性

3.1 React 编译器

React 19 引入了开源 React 编译器(React Fizz),自动优化组件渲染,消除手动使用 useMemouseCallback 的需求。

示例:无需手动优化的组件

import React from "react";

interface Item {
  id: number;
  name: string;
}

const ItemList: React.FC<{ items: Item[] }> = ({ items }) => {
  // 无需 useMemo 或 useCallback,编译器自动优化
  const filteredItems = items.filter((item) => item.id > 0);

  return (
    <ul>
      {filteredItems.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
};

说明

  • 编译器将 JSX 转换为优化的 JavaScript,减少不必要的重新渲染。
  • 需要安装 babel-plugin-react-compiler

babel.config.js

const ReactCompilerConfig = {
  sources: (filename: string) => filename.includes("src/components"),
};

module.exports = {
  plugins: [["babel-plugin-react-compiler", ReactCompilerConfig]],
};

最佳实践

  • 在项目中逐步启用编译器,先在非关键目录测试。
  • 确保代码符合编译器要求(如避免动态依赖)。

3.2 Server Components

Server Components 允许在服务器上渲染组件,减少客户端 JavaScript 量,提升性能和 SEO。

示例:Server Component

// server/HomePage.server.tsx
import { db } from "../db";

async function HomePage() {
  const posts = await db.posts.findMany();
  return (
    <div>
      <h1>Latest Posts</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}

export default HomePage;

说明

  • 使用 "use server" 指令定义 Server Components 或 Server Actions。
  • Server Components 不能包含客户端交互逻辑(如 useState)。
  • 需要配合支持 Server Components 的框架(如 Next.js 15)。

最佳实践

  • 将数据获取逻辑放在 Server Components 中。
  • 使用 Client Components 处理交互逻辑。
  • 确保 Server Components 不依赖客户端 API(如 window)。

3.3 Server Actions

Server Actions 允许 Client Components 调用服务器上的异步函数,简化数据操作。

示例:Server Action

// server/actions.ts
"use server";

import { db } from "../db";

export async function createTodo(formData: FormData) {
  const title = formData.get("title") as string;
  await db.todos.create({ title });
}

使用 Server Action

// client/TodoForm.tsx
import { useActionState } from "react";
import { createTodo } from "../server/actions";

const TodoForm: React.FC = () => {
  const [state, dispatch, isPending] = useActionState(createTodo, null);

  return (
    <form action={dispatch}>
      <input type="text" name="title" disabled={isPending} />
      <button type="submit" disabled={isPending}>
        {isPending ? "Creating..." : "Create Todo"}
      </button>
      {state?.message && <p>{state.message}</p>}
    </form>
  );
};

说明

  • useActionState 管理表单提交状态,自动处理 pending 状态和错误。
  • Server Actions 需在支持的框架中配置(如 Next.js)。

最佳实践

  • 使用 TypeScript 验证 formData 的类型。
  • 提供用户反馈(如 loading 状态或错误信息)。
  • 避免在 Server Actions 中执行复杂逻辑,保持单一职责。

3.4 新 Hooks

3.4.1 useOptimistic

useOptimistic 用于乐观更新,提供即时 UI 反馈。

示例:乐观更新

import React, { useState, useOptimistic } from "react";
import { createTodo } from "../server/actions";

const OptimisticTodo: React.FC = () => {
  const [todos, setTodos] = useState<string[]>([]);
  const [optimisticTodos, addOptimisticTodo] = useOptimistic(
    todos,
    (state, newTodo: string) => [...state, newTodo]
  );

  const handleSubmit = async (formData: FormData) => {
    const title = formData.get("title") as string;
    addOptimisticTodo(title);
    await createTodo(formData);
    setTodos((prev) => [...prev, title]);
  };

  return (
    <form action={handleSubmit}>
      <input type="text" name="title" />
      <button type="submit">Add Todo</button>
      <ul>
        {optimisticTodos.map((todo, index) => (
          <li key={index}>{todo}</li>
        ))}
      </ul>
    </form>
  );
};

说明

  • useOptimistic 在服务器响应前显示临时状态。
  • 实际响应返回后,状态会同步更新。

最佳实践

  • 用于低风险操作(如添加评论、点赞)。
  • 确保服务器操作与乐观更新逻辑一致。

3.4.2 useFormStatus

useFormStatus 提供表单提交状态,简化表单管理。

示例:表单状态

import React, { useFormStatus } from "react";

const SubmitButton: React.FC = () => {
  const { pending } = useFormStatus();
  return (
    <button type="submit" disabled={pending}>
      {pending ? "Submitting..." : "Submit"}
    </button>
  );
};

const Form: React.FC = () => {
  return (
    <form action="/api/submit">
      <input type="text" name="name" />
      <SubmitButton />
    </form>
  );
};

最佳实践

  • useFormStatus 用于子组件,避免 prop 钻透。
  • 结合 useActionState 提供完整的表单体验。

3.4.3 use

use Hook 用于读取 Promise 或上下文,集成 Suspense。

示例:数据获取

import React, { use, Suspense } from "react";

interface Comment {
  id: number;
  text: string;
}

const Comments: React.FC<{ commentsPromise: Promise<Comment[]> }> = ({
  commentsPromise,
}) => {
  const comments = use(commentsPromise);
  return (
    <ul>
      {comments.map((comment) => (
        <li key={comment.id}>{comment.text}</li>
      ))}
    </ul>
  );
};

const Page: React.FC = () => {
  const commentsPromise = fetch("https://api.example.com/comments").then(
    (res) => res.json()
  );
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Comments commentsPromise={commentsPromise} />
    </Suspense>
  );
};

说明

  • use 暂停渲染直到 Promise 解析,需配合 Suspense
  • 适合 Server Components 或流式渲染。

最佳实践

  • 始终用 Suspense 包裹 use 调用。
  • 提供友好的加载 UI。

3.5 Document Metadata

React 19 支持在组件中直接渲染 <title><meta> 等标签,自动提升到 <head>,简化 SEO 管理。

示例:元数据

import React from "react";

const HomePage: React.FC = () => {
  return (
    <>
      <title>My App - Home</title>
      <meta name="description" content="Welcome to my React 19 app" />
      <h1>Home Page</h1>
    </>
  );
};

最佳实践

  • 使用 DocumentHead 组件(若框架支持)集中管理元数据。
  • 确保元数据与页面内容一致,提升 SEO 效果。

3.6 Asset Loading

React 19 优化了资源(如图片、脚本、样式)加载,支持后台预加载和 Suspense。

示例:异步脚本

import React from "react";

const Analytics: React.FC = () => {
  return <script async src="https://example.com/analytics.js" />;
};

说明

  • 异步脚本可渲染在组件树任意位置,React 自动去重并优化加载。

最佳实践

  • 使用 preloadprefetch API 优化关键资源。
  • 结合 Suspense 管理资源加载状态。

4. TypeScript 集成

React 19 增强了 TypeScript 支持,推荐使用最新类型定义。

4.1 Props 类型

为 Props 定义接口,确保类型安全。

示例

interface ButtonProps {
  label: string;
  onClick: () => void;
  disabled?: boolean;
}

const Button: React.FC<ButtonProps> = ({ label, onClick, disabled }) => {
  return (
    <button onClick={onClick} disabled={disabled}>
      {label}
    </button>
  );
};

4.2 Refs

React 19 支持直接传递 ref 作为 Props,无需 forwardRef

示例

import React, { useRef } from "react";

const Input: React.FC<{ ref: React.RefObject<HTMLInputElement> }> = ({
  ref,
}) => {
  return <input ref={ref} />;
};

const App: React.FC = () => {
  const inputRef = useRef<HTMLInputElement>(null);

  const focusInput = () => {
    inputRef.current?.focus();
  };

  return (
    <div>
      <Input ref={inputRef} />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
};

最佳实践

  • 使用 React.RefObject 声明 Ref 类型。
  • 检查 ref.current 是否存在(strictNullChecks)。

5. 性能优化

5.1 React 编译器

如前所述,React 编译器自动优化渲染,减少手动 memoization。

5.2 Suspense 与 Lazy Loading

使用 React.lazySuspense 实现代码分割。

示例

import React, { Suspense, lazy } from "react";

const HeavyComponent = lazy(() => import("./HeavyComponent"));

const App: React.FC = () => {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <HeavyComponent />
    </Suspense>
  );
};

最佳实践

  • 对大型组件使用 React.lazy 减少初始加载时间。
  • 提供清晰的加载 UI。

5.3 自动批处理

React 19 扩展了自动批处理,减少不必要的重新渲染。

示例

import React, { useState } from "react";

const BatchUpdate: React.FC = () => {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  const handleClick = () => {
    setTimeout(() => {
      setCount((c) => c + 1);
      setFlag((f) => !f); // React 19 仅触发一次渲染
    }, 1000);
  };

  return <button onClick={handleClick}>Update</button>;
};

6. 错误处理

React 19 改进了错误处理,支持更清晰的错误信息和 Error Boundary。

示例:Error Boundary

import React from "react";

interface ErrorBoundaryProps {
  fallback: React.ReactNode;
  children: React.ReactNode;
}

interface ErrorBoundaryState {
  hasError: boolean;
}

class ErrorBoundary extends React.Component<
  ErrorBoundaryProps,
  ErrorBoundaryState
> {
  state: ErrorBoundaryState = { hasError: false };

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  componentDidCatch(error: Error, info: React.ErrorInfo) {
    console.error("Error:", error, info);
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback;
    }
    return this.props.children;
  }
}

const App: React.FC = () => {
  return (
    <ErrorBoundary fallback={<h1>Something went wrong</h1>}>
      <ThrowsError />
    </ErrorBoundary>
  );
};

最佳实践

  • 使用 onUncaughtErroronCaughtError 捕获全局错误。
  • 提供用户友好的错误 UI。

7. 最佳实践

  1. 使用函数组件和 Hooks:优先使用函数组件,避免类组件。
  2. 启用 React 编译器:在支持的环境中启用编译器以简化优化。
  3. TypeScript 优先:使用 TypeScript 确保类型安全,减少运行时错误。
  4. Server Components 与 Client Components 分离:将数据获取放在 Server Components,交互逻辑放在 Client Components。
  5. 模块化与代码分割:使用 React.lazy 和模块别名组织代码。
  6. 测试与调试
    • 使用 @testing-library/react 进行单元测试。
    • 安装 React DevTools 调试组件树和性能。
  7. SEO 优化:使用 Document Metadata 管理 <head> 标签。
  8. 渐进式升级:在非生产环境测试 React 19 新特性,逐步迁移。
  9. 避免过早优化:依赖 React 编译器,减少手动 useMemouseCallback
  10. 保持一致性:遵循 PascalCase 组件命名,kebab-case 文件命名。

8. 迁移到 React 19

8.1 关键变更

  • 移除旧 APIReactDOM.renderReactDOM.hydratecreateRoothydrateRoot 取代。
  • 新 JSX 转换:必须使用 react-jsx
  • 移除 forwardRef:直接传递 ref 作为 Props。
  • 废弃 react-test-renderer:推荐使用 @testing-library/react

8.2 迁移步骤

  1. 更新依赖到 react@19.1react-dom@19.1
  2. 运行 npx types-react-codemod@latest preset-19 ./src 自动修复类型问题。
  3. 更新 JSX 转换配置(tsconfig.json 或 Babel)。
  4. 测试 Server Components 和 Server Actions(需框架支持)。
  5. 使用 React 19 升级指南(https://react.dev/reference/react/upgrade-to-19)。

9. 资源与进一步学习