iT邦幫忙

2025 iThome 鐵人賽

DAY 18
0

本文參考自 Dan Abramov 的文章 Before You memo()Overreacted),並整理成學習筆記。

前言

在 React 中,當我們發現某個畫面效能不好時,第一個直覺常常是「加上 React.memo 就能解決」。
但事實上,memo 並不是最佳的第一步。這篇文章要教我們在「急著用 memo 前」應該先檢查的幾件事。

核心概念

Dan 提出兩個比 memo 更基礎的思考方向:

  1. Move State Down(把 state 往下移)

    • 如果 state 只會影響某個小範圍,應該把它放到那個區塊裡,而不是放在上層。
    • 這樣可以避免整個父層 component 重渲,進而影響到其他不相關的子元件。
  2. Lift Content Up(把不會變的 UI 提出去)

    • 把穩定、不會依賴 state 的 UI 提到外層或 children,這樣當 state 改變時,這些部分就能跳過 re-render。

換句話說,在用 memo 前,應該先想想:是不是因為 state 放錯地方或 UI 沒有切分好,導致不必要的重新渲染?

範例

問題程式

function App() {
  const [color, setColor] = useState("red");

  return (
    <div>
      <input value={color} onChange={(e) => setColor(e.target.value)} />
      <p style={{ color }}>Hello, world!</p>
      <ExpensiveTree /> {/* 很重的 component */}
    </div>
  );
}

這裡的問題是:每次 color 改變,整個 App 都要 re-render,包括 ExpensiveTree,即使它根本沒用到 color

改進方法:Move State Down

function App() {
  return (
    <>
      <ColorForm />
      <ExpensiveTree />
    </>
  );
}

function ColorForm() {
  const [color, setColor] = useState("red");
  return (
    <>
      <input value={color} onChange={(e) => setColor(e.target.value)} />
      <p style={{ color }}>Hello, world!</p>
    </>
  );
}

現在,只有 ColorForm 會重新渲染,ExpensiveTree 不受影響。

改進方法:Lift Content Up

function App() {
  return (
    <ColorPicker>
      <ExpensiveTree />
    </ColorPicker>
  );
}

function ColorPicker({ children }) {
  const [color, setColor] = useState("red");
  return (
    <div style={{ color }}>
      <input value={color} onChange={(e) => setColor(e.target.value)} />
      {children}
    </div>
  );
}

只要 children 本身不依賴 color,就不會因為 color 變動而被重新渲染。

常見錯誤 / 誤解

  • 誤以為套上 React.memo 就足夠:其實若 props 是物件 / 陣列且每次都重建,memo 判斷會失效。
  • 把 state 放得太高:即使 memo,也可能因為 state 在高層造成很多無關子樹被重渲。
  • over-memo 化:到處套 React.memo 或 useMemo 反而增加複雜度、降低可讀性。

面試回答

中文

我不會一開始就用 React.memo。
在加上 memo 之前,我會先調整元件結構,像是把 state 往下移,或者把穩定的 UI 往上抽出來。
另外,React.memo 本身也有一些缺點:

  • 它需要比較 props,這本身也有開銷。
  • 如果 props 是物件或 callback,每次 render 都產生新參考,就會讓 memo 失效。
  • 過度使用 memo 會讓程式碼更難閱讀與維護。
    所以我只會在 真的很昂貴、而且 props 穩定的元件 上使用 React.memo。

英文

I don’t use React.memo as the first step.
Before adding memo, I restructure components by moving state down or lifting stable UI up.
Also, React.memo itself has trade-offs:

  • It still has a cost because React needs to compare props.
  • It can be broken if props are objects or callbacks that change every render.
  • Too much memo makes code harder to read and maintain.

So I use it only for expensive components where props are stable.

總結

  • React.memo 不是效能優化的第一步。
  • 先檢查 state 放的位置是否正確。
  • 先切分 UI 結構,把不變的部分抽出來。
  • 在結構合理後,再使用 memo 會更有效率。

上一篇
Day 17 — 什麼是 React.memo
下一篇
Day 19:function component vs Class component 的差異
系列文
30 天掌握 React & Next.js:從基礎到面試筆記19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言