Featured image of post React 編譯器:告別手動記憶Featured image of post React 編譯器:告別手動記憶

React 編譯器:告別手動記憶

自動建置時編譯器如何處理清單和回呼的反應性渲染最佳化。

介紹

多年來,React 開發人員一直使用 useMemouseCallbackReact.memo 和各種狀態管理啟發式方法手動優化重新渲染。 React Compiler(以前稱為 React Forget)完全改變了這個範例。它是一個建置時工具,透過在編譯時分析反應依賴關係來自動記憶 React 元件、鉤子和值,從而無需手動最佳化鉤子。


手動記憶的問題

考慮一個典型的過濾列表元件:

function UserList({ users, filter }) {
  const filtered = useMemo(
    () => users.filter(u => u.name.includes(filter)),
    [users, filter]
  );

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

  return (
    <ul>
      {filtered.map(user => (
        <UserRow key={user.id} user={user} onClick={handleClick} />
      ))}
    </ul>
  );
}

const UserRow = React.memo(({ user, onClick }) => (
  <li onClick={() => onClick(user.id)}>{user.name}</li>
));

這是可行的,但它很冗長,容易出錯(依賴項數組遺失或不正確),並且很容易忘記。大列表中缺少 useMemo 會導致不必要的重新渲染;不正確的依賴數組會導致陳舊的閉包。


什麼是 React 編譯器?

React Compiler 是一個建置時插件(Babel / SWC),可以自動理解 React 元件的反應性模型。它會自動轉譯您的程式碼以包含記憶邏輯:

// You write this:
function Welcome({ name }) {
  const greeting = `Hello, ${name}!`;
  return <p>{greeting}</p>;
}
// Compiler outputs effectively this:
function Welcome({ name }) {
  const $ = React.cache(/* ... */);
  let greeting = $.refresh('greeting', name => `Hello, ${name}!`, [name]);
  return $.memo('element', () => <p>{greeting}</p>, [greeting]);
}

編譯器會偵測哪些值依賴 props、state 或其他反應值,並且僅在這些依賴項發生變化時重新計算它們。


它是如何運作的

編譯器分三個階段運作:

  1. 反應性值偵測 — 它遍歷抽象語法樹 (AST),以識別哪些變數源自 props、state、hooks 或其他反應性來源。

  2. 依賴圖建構 — 它建立連接反應值的依賴圖。任何僅源自非反應源的值均被視為靜態值。

  3. 記憶化程式碼產生 — 它產生具有內建快取失效功能的最佳化 JavaScript。運作時使用類似訊號的細粒度依賴追蹤機制。

編譯器遵循的關鍵規則:

規則行為
Props 和 state 總是反應性的任何派生值都會自動記憶
非反應常數被提升沒有增加記憶開銷
回呼預設穩定不需要 useCallback
元件主體最佳化僅在反應性依賴發生變化時才重新執行

與建置工具集成

維特

// vite.config.js
import react from '@vitejs/plugin-react';

export default {
  plugins: [
    react({
      babel: {
        plugins: [['babel-plugin-react-compiler', { target: '18' }]],
      },
    }),
  ],
};

Next.js

// next.config.js
module.exports = {
  experimental: {
    reactCompiler: true,
  },
};

你可以刪除什麼

啟用 React 編譯器後,您不再需要:

  • useMemo() — 自動值記憶
  • useCallback() — 自動功能穩定性
  • React.memo() — 自動元件記憶(編譯器包裝渲染輸出)
  • 大多數情況下手動依賴數組

編譯器甚至可以優化難以手動處理的模式,例如條件掛鉤 - 儘管您仍然應該遵循掛鉤規則。


注意事項和最佳實踐

雖然編譯器可以處理絕大多數情況,但某些情況需要謹慎:

警告推薦
可變引用useRef 突變未被追蹤使用 useState 或觸發明確重新渲染
外部儲存 — 值不是來自 React包裹在 useSyncExternalStore
複雜的副作用useEffect 具有非反應性依賴如果需要,添加明確依賴
遺留上下文 — 類別元件上下文遷移到現代 useContext

此編譯器對於遵循標準 React 模式的程式碼庫最為有效。高度命令式程式碼可能帶來的好處較少。


結論

React 編譯器代表了從手動自動記憶的根本轉變。透過在建置時分析反應性依賴關係,它消除了整個類別的效能錯誤和樣板檔案。對於現有項目,啟用編譯器需要最少的配置;對於新項目,它改變了你對 React 效能的看法——你只需編寫聲明性元件,然後讓編譯器處理其餘的事情。