React 19 新特性完全指南:Actions、use()、Server Components 與編譯器最佳化

前端工程(更新於 2026年5月6日)

React 19:框架級的範式升級

React 19 不只是 API 更新,而是從「庫」到「全棧框架」的定位轉變。Server Components、Actions、Compiler 三大特性重新定義了 React 應用的寫法。

特性 解決的問題 影響範圍
Form Actions 表單提交的樣板程式碼 所有表單互動
use() Hook 條件式資料載入 資料獲取模式
Server Components 客戶端包體積 全架構
React Compiler 手動 memo 最佳化 效能
ref as prop forwardRef 樣板程式碼 元件 API
Document Metadata SEO/head 管理 SSR 應用

一、Form Actions:告別表單樣板程式碼

傳統寫法

function LoginForm() {
  const [pending, setPending] = useState(false);
  const [error, setError] = useState(null);

  async function handleSubmit(e) {
    e.preventDefault();
    setPending(true);
    setError(null);
    try {
      const formData = new FormData(e.target);
      await login(formData.get('email'), formData.get('password'));
    } catch (err) {
      setError(err.message);
    } finally {
      setPending(false);
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="email" type="email" />
      <input name="password" type="password" />
      <button disabled={pending}>{pending ? '登入中...' : '登入'}</button>
      {error && <p>{error}</p>}
    </form>
  );
}

React 19 寫法

async function loginAction(formData) {
  // 直接在 Server 上執行,無需手動管理 pending/error
  await login(formData.get('email'), formData.get('password'));
}

function LoginForm() {
  return (
    <form action={loginAction}>
      <input name="email" type="email" />
      <input name="password" type="password" />
      <SubmitButton />
    </form>
  );
}

// useActionStatus 自動追蹤提交狀態
function SubmitButton() {
  const { pending } = useActionStatus();
  return <button disabled={pending}>{pending ? '登入中...' : '登入'}</button>;
}

減少程式碼量:約 60%。不再需要 onSubmitpreventDefault、手動 pending/error 狀態。

useActionState:管理表單狀態

function LoginForm() {
  const [state, formAction, isPending] = useActionState(
    async (prevState, formData) => {
      try {
        await login(formData.get('email'), formData.get('password'));
        return { success: true };
      } catch (err) {
        return { error: err.message };
      }
    },
    null
  );

  return (
    <form action={formAction}>
      <input name="email" type="email" />
      <input name="password" type="password" />
      <button disabled={isPending}>登入</button>
      {state?.error && <p className="error">{state.error}</p>}
    </form>
  );
}

二、use() Hook:條件式資料載入

use() 是 React 第一個可以在條件語句和迴圈中呼叫的 Hook。

讀取 Promise

function UserProfile({ userPromise }) {
  // 可以在條件中使用!
  if (showProfile) {
    const user = use(userPromise);
    return <h1>{user.name}</h1>;
  }
  return null;
}

讀取 Context

function ThemeToggle() {
  // 之前必須用 useContext,現在可以用 use
  const theme = use(ThemeContext);
  return <button onClick={toggle}>{theme}</button>;
}

Suspense 整合

function UserPage({ userPromise }) {
  return (
    <Suspense fallback={<Spinner />}>
      <UserProfile userPromise={userPromise} />
    </Suspense>
  );
}

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

三、Server Components 正式穩定

Server vs Client 元件

// Server Component(預設)
// - 在服務端渲染,不傳送 JS 到客戶端
// - 可以直接存取資料庫、檔案系統
// - 不能使用 useState、useEffect、事件處理

async function BlogList() {
  const posts = await db.query('SELECT * FROM posts');
  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>
          <h2>{post.title}</h2>
          <LikeButton postId={post.id} /> {/* Client Component */}
        </li>
      ))}
    </ul>
  );
}
// Client Component
'use client';
// - 在客戶端渲染(也可 SSR)
// - 可以使用所有 Hook
// - 打包傳送到客戶端

function LikeButton({ postId }) {
  const [liked, setLiked] = useState(false);
  return <button onClick={() => setLiked(!liked)}>❤️</button>;
}

Server Actions

'use server';

async function createPost(formData) {
  const title = formData.get('title');
  const content = formData.get('content');
  await db.insert('posts', { title, content });
  revalidatePath('/blog');
}
// Client 元件中使用 Server Action
function NewPostForm() {
  return (
    <form action={createPost}>
      <input name="title" />
      <textarea name="content" />
      <button type="submit">發布</button>
    </form>
  );
}

四、React Compiler:自動效能最佳化

React Compiler(原 React Forget)自動插入 memo 邏輯,開發者不再需要手動使用 useMemouseCallbackmemo

編譯前

function ExpensiveComponent({ items, filter }) {
  // 開發者手動最佳化
  const filtered = useMemo(
    () => items.filter(i => i.category === filter),
    [items, filter]
  );

  const handleClick = useCallback((id) => {
    console.log(id);
  }, []);

  return <List items={filtered} onClick={handleClick} />;
}

編譯後(自動最佳化)

function ExpensiveComponent({ items, filter }) {
  // 直接寫,編譯器自動 memoize
  const filtered = items.filter(i => i.category === filter);
  const handleClick = (id) => console.log(id);
  return <List items={filtered} onClick={handleClick} />;
}

啟用 Compiler

// next.config.js
const nextConfig = {
  experimental: {
    reactCompiler: true,  // 或 'unstable' 獲取最新特性
  },
};

Compiler 的限制

不自動最佳化的場景 原因
修改傳入的 props/mutable 物件 副作用無法追蹤
在 Hook 外部建立的閉包 生命週期不明確
使用 arguments 物件 非標準用法

五、ref 作為 prop:告別 forwardRef

React 18 寫法

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

React 19 寫法

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

// 使用
<Input ref={inputRef} placeholder="請輸入" />;

六、Document Metadata

React 19 原生支援 <title><meta><link> 在元件中宣告:

function BlogPost({ post }) {
  return (
    <>
      <title>{post.title}</title>
      <meta name="description" content={post.excerpt} />
      <link rel="canonical" href={`https://example.com/blog/${post.slug}`} />
      <article>
        <h1>{post.title}</h1>
        <p>{post.content}</p>
      </article>
    </>
  );
}

React 自動將這些標籤提升到 <head> 中,不同路由的 metadata 自動去重替換。


七、其他改進

useOptimistic:樂觀更新

function LikeButton({ postId, initialLiked }) {
  const [liked, addOptimisticLike] = useOptimistic(initialLiked);

  async function handleLike() {
    addOptimisticLike(true); // 立即顯示點讚
    await likePost(postId);  // 後臺同步
  }

  return <button onClick={handleLike}>{liked ? '❤️' : '🤍'}</button>;
}

useSyncExternalStore 改進

支援訂閱 getSnapshot 返回不同值但語義等價的 store(如帶快取的資料獲取)。

Custom Elements 完整支援

React 19 正確處理 Custom Elements 的屬性和事件:

<my-custom-element someProp="value" onCustomEvent={handler} />

遷移清單

變更 影響 行動
forwardRefref prop 所有使用 forwardRef 的元件 遷移
useMemo/useCallback 手動 memo 啟用 Compiler 後逐步移除
onSubmitaction 表單元件 重構為 Actions
useContextuse() Context 消費 可選遷移
ref.current.cleanup() ref callback 清理 新模式
字串 ref 廢棄 舊程式碼 遷移為 callback/object ref

Codemod 工具

npx react-codemod@latest react-19

自動處理大部分 Breaking Changes,包括 forwardRef 遷移、字串 ref 替換等。

#React#React 19#Server Components#前端框架