iT邦幫忙

2021 iThome 鐵人賽

DAY 7
0
Modern Web

用30天更加認識 React.js 這個好朋友系列 第 7

Day7-在認識 useMemo 前,先認識 React.memo

  • 分享至 

  • xImage
  •  

今天介紹的是避免重新渲染的 HOC(Higher Order Component) React.memo,透過它可以對元件重新渲染的時機做出控制。

React.memo

首先,我們知道當父元件 context、state 和 props 其中之一改變時會重新渲染,底下的子元件也會跟著渲染,但實際上父元件只有 state 改變時,有些情況是沒有必要渲染底下的子元件的。

功用

而 React.memo 的功用就是避免一些不必要的渲染,透過 React.memo 包住子元件,它會記錄之前的 props 內容,只有當記憶中的 props 改變時(但 state、context 不變)才會重新渲染元件。

語法

React.memo(Component, [areEqual(prevProps, nextProps)]);

React.memo 共接收兩個參數,第一個是要包住的元件,第二個是可以自訂比較 props 的方法,回傳 false 時會重新渲染元件。

特性

React.memo 在比較 props 改變時,背後是使用 Object.is() 去判定,當 props 是原始型別時,比較的是值是否相同,當 props 是物件型別時,比較的是記憶體位置(by reference)。

所以父元件重新渲染時,重新提供新的 props 給子元件,如果是物件型別的話,即使內容的值完全一樣,但還是會導致 memo 失效,重新渲染子元件。

此原因也是使用 useMemo 的其中一個原因

解決辦法

  1. 使用 memo 的第二個參數,自訂比較 props 的方法。
  2. 使用 useCallback、useMemo,因此 memo 與 useCallback、useMemo 經常被一起使用。

注意

  • 經常變更不一樣的 props 不建議使用 memo。
  • 因為使用 memo 也是需要消耗記憶效能,所以要評估元件的大小是否值得使用。

範例

首先在 App.jsx 內設定好要傳遞的 props,這裡刻意將不會在子元件用到的 step 和 count 傳入,用來示範 React.memo 的第二個參數作用。

App.jsx

import React, { useState } from "react";
import Child from "./Child";
import ChildMemo from "./ChildMemo";

const App = () => {
  const [step, setStep] = useState(0);
  const [count, setCount] = useState(0);
  const [number, setNumber] = useState(0);

  return (
    <>
      <button onClick={() => setStep(step + 1)}>step is : {step} </button>
      <button onClick={() => setCount(count + 1)}>count is : {count} </button>
      <button onClick={() => setNumber(count + step)}>
        number is : {number}
      </button>
      <hr />
      <Child step={step} count={count} number={number} /> <hr />
      <ChildMemo step={step} count={count} number={number} />
    </>
  );
};

export default App;

在 Child.jsx,不使用 React.memo,所以點擊 step 和 count 按鈕改變 state 都會導致 re-render

Child.jsx

import React from "react";

export default (props) => {
  console.log(`Child re-render`);
  return <p>number is : {props.number}</p>;
};

在 ChildMemo.jsx 中,將元件用 memo 包覆,並自定義了 props 比較的方法 isEqual,不管怎麼點擊 step 和 count 按鈕 isEqual 都會回傳 false,只有當 number 更新時才 re-render。

ChildMemo.jsx

import React, { memo } from "react";

const isEqual = (prevProps, nextProps) => {
  if (prevProps.number !== nextProps.number) {
    return false;
  }
  return true;
};

export default memo((props) => {
  console.log(`ChildMemo re-render`);
  return <p>number is : {props.number}</p>;
}, isEqual);

程式範例(codesandbox)


上一篇
Day6-React Hook 篇-useReducer
下一篇
Day8-React Hook 篇-認識 useMemo
系列文
用30天更加認識 React.js 這個好朋友33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言