Day7-在认识 useMemo 前,先认识 React.memo

今天介绍的是避免重新渲染的 HOC(Higher Order Component) React.memo,透过它可以使我们提升 React 网站的效能。

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 可惜的是它和 JS 一样也是透过 by value & by reference 去判断两个比较的值是否一样,也可以说是 shallow compare,所以当 props 是物件型别时,比较的是记忆体位置(by reference)。

父元件重新渲染时,重新提供新的 props 给子元件,如果是物件型别的话,即使内容的值完全一样,但还是会导致 memo 失效,重新渲染子元件。

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

解决办法

  1. 使用 memo 的第二个参数,自订比较 props 的方法。
  2. 使用 useCallback,因此 memo 与 useCallback 经常被一起使用。

注意

  • 经常变更不一样的 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)


<<:  [ Day 06 ] Function Component

>>:  [Day 21] 闭包 (Closure)是什麽?

第4砍 - 蓄势待发

今晚我想来点... 麻而不辣的 linker script [叮咚] 您的外送餐点到瞜, 已经依照您...

Day31 -- Whack A Mole

目标 今天要来做的是打地鼠 Step1 const holes = document.querySe...

DAY2-为什麽需要用VUE???

这边是我在上次面试时有被问到跟自己想搞清楚的几个问题 第一个问题就是什麽是MVVM? 如果VIEW上...

Day30 javascript 总结

今天是最後一天,咱们今天不看程序码,来谈谈现在我们已经学习了 JavaScript,做个总结顺便想想...

Day 29 Realm的练习-使用者注册系统(3/3)

今天我们把tableView做更新 func updateData(){ users = [] le...