iT邦幫忙

2024 iThome 鐵人賽

DAY 24
0
Modern Web

現在就學React.js 系列 第 24

提升組件的效能-memo - Day24

  • 分享至 

  • xImage
  •  

在 React 中父組件重新渲染時,所有子組件也會重新渲染,即便這些子組件的 props 沒有發生變化。使用 memo 可以避免不必要的渲染,從而提升應用效能。

memo 是通過「記住」組件的渲染結果,當 props 沒有變化時,它會返回先前的渲染結果,避免再次執行渲染操作。

memo 的使用有概念後,透過兩個範例來更加理解它的使用與好處吧!

範例一:未使用 memo 的情況

在這個範例中,有一個父組件 App,內部包含一個 TodoItem 子組件。即便 TodoItem 組件的 props 沒有改變,每次父組件 App 重新渲染時,TodoItem 還是會跟著被重新渲染。


import { useState } from 'react'

// 定義 Todo 列表項目
const TodoItem = ({ todo }) => {
  console.log('Rendering Todo:', todo)
  return <p>{todo}</p>
}

const App = () => {
  const [count, setCount] = useState(0)
  const [todos, setTodos] = useState(['Learn React'])

  const increment = () => {
    setCount(c => c + 1)
  }

  const addTodo = () => {
    setTodos(t => [...t, 'New Todo'])
  }

  return (
    <div>
      <div>
        <h2>My Todos</h2>
        {todos.map((todo, index) => (
          <TodoItem key={index} todo={todo} />
        ))}
        <button onClick={addTodo}>Add Todo</button>
      </div>
      <hr />
      <div>
        Count: {count}
        <button onClick={increment}>+</button>
      </div>
    </div>
  )
}

export default App

在這範例中,按下「Count +」按鈕,即便 todos 沒有變化,TodoItem 組件還是會重新渲染,這會影響效能,特別是在列表項目非常多的情況下。

範例二:使用 memo 進行優化

使用 React.memo 來解決這個問題。當 TodoItemprops 沒有變化時,它不會重新渲染。

import { useState, memo } from 'react'

// 定義 Todo 列表項目,並使用 memo 來優化
const TodoItem = memo(({ todo }) => {
  console.log('Rendering Todo:', todo)
  return <p>{todo}</p>
})

const App = () => {
  const [count, setCount] = useState(0)
  const [todos, setTodos] = useState(['Learn React'])

  const increment = () => {
    setCount(c => c + 1)
  }

  const addTodo = () => {
    setTodos(t => [...t, 'New Todo'])
  }

  return (
    <div>
      <div>
        <h2>My Todos</h2>
        {todos.map((todo, index) => (
          <TodoItem key={index} todo={todo} />
        ))}
        <button onClick={addTodo}>Add Todo</button>
      </div>
      <hr />
      <div>
        Count: {count}
        <button onClick={increment}>+</button>
      </div>
    </div>
  )
}

export default App

範例說明:

  • TodoItem 使用 memo:透過 memoTodoItem 組件只有在其 props 改變時才會重新渲染。當按下「Count +」按鈕時,count 的狀態變化不會影響 TodoItem,因為 todos 陣列沒有改變,因此避免了不必要的渲染。

使用 memo 的注意事項

  1. 僅適用於純函數組件

    memo 只適用於純函數組件,組件依賴於 props,而且不會修改外部狀態或引發副作用。

  2. 謹慎使用場景

    雖然 memo 可以提升效能,但過度使用會增加程式的複雜性。對於渲染成本較低的組件,可能不需要用 memo 進行優化,避免適得其反。

  3. props 比對成本

    memo 使用 Object.is 來比較 props 是否變化。這個比對過程本身會產生一定的成本,對簡單的組件,渲染成本可能低於 memo 的比對成本,這時反而不應使用 memo

結論

memo 是 React 可以用來優化組件效能的工具,當發現某些組件在不必要的情況下被多次重新渲染,不妨考慮使用 memo 來記住組件的渲染結果,從而避免重複渲染並提升效能吧!

後記

本文將會同步更新到我的部落格

黃禎平 – Medium


上一篇
用useMemo優化效能 - Day23
下一篇
useCallback的使用時機 - Day25
系列文
現在就學React.js 31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言