[Bonus 系列] - 使用 useCallback & useMemo 的正确时机是什麽?

前言

虽然说之前已经认识了 useCallback、useMemo,但有时还是对於什麽时候要用它们的时机有些模糊,所以就透过这篇文章厘清观念。

首先要知道一点是如果没有必要可以不用去用它们,盲目的使用反而更耗效能,因为它们在 React 底层记忆值也是需要消耗效能的。

Referential Equality

在此先复习一下 Referential Equality,对於理解後面的内容会有所帮助。

我们知道阵列、物件、函式等物件型别拥有 call by reference 的特性,所以即使有两个物件它们里面的元素、属性、函式内容都一样,在做 === 比较时仍然会是 false。

const hero1 = {
  name: 'Batman'
};

const hero2 = {
  name: 'Batman'
};

console.log(hero1 === hero1); // => true
console.log(hero1 === hero2); // => false

这样跟 React 又有什麽关系?让我们继续看下去!

useCallback 使用时机

Referential Equality 案例 1

在下面的范例可以看到一个被 React.memo() 包覆的元件 Child,而且接收到一个函式 onClick 当作 props。

父元件重新渲染时,虽然都还是同一个函式,但函式被重新产生了,所以 React.memo() 会以为传入的 props 改变而重新渲染 Child 元件,所以加上了 useCallback。

function Parent() {
  const [count, setCount] = useState(0);

  const onClick = useCallback(() => {
    console.log('click');
  }, []);

  return (
    <>
      <Foo onClick={onClick} />
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>count increment</button>
    </>
  );
}
const Child = memo({ onClick }) => {
  // ...略

  return (
    <>
     // ...
     <button onClick={onClick}>可点击</button>
    </>
  )
});

Referential Equality 案例 2

useEffect 的 dependency array 的其中一个元素为物件型别时,若物件重新产生就会被 useEffect 当作 dependency array 改变,像以下的例子就造成了 useEffect 无限 render,所以也需要加上 useCallback。

跟此范例类似的例子在 pjchender 大大的 从 Hooks 开始,让你的网页 React 起来 Day20 篇 也有提到,有兴趣的读者可以跳到"在 useEffect 的 dependencies 中放入函式 - useCallback 的使用"的段落去阅读。

const App = () => {
  const [id, setId] = useState(1);
  const [detail, setDetail] = useState("");

  const getDetail = useCallback(() => {
    fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
    .then(res => res.json())
    .then(json => {
      setDetail(json); // state updated
    }));
  }, [id]);

  useEffect(() => {
    getDetail();
  }, [getDetail]);

  return (
    <>
      <p>{detail.name}</p>
      <p>Current id: {id}</p>
      <button onClick={() => setId(id + 1)}>id increment</button>
    </>
  );
}

useMemo 使用时机

1. Referential Equality

Referential Equality 的概念也可以套用在 useMemo,所以也可以留意一下 useEffect 的 dependency array。

const App = ({ param1, param2 }) => {
  const params = useMemo(() => {
    return { param1, param2, param3: 1 };
  }, [param1, param2]);

  useEffect(() => {
    callApi(params);
  }, [params]);
}

2. 计算开销较大的值

例如 filter 很多元素的阵列、复杂数学运算

参考资料 & 推荐阅读

How To Use Memoization To Drastically Increase React Performance

When to useMemo and useCallback

如何错误地使用 React hooks useCallback 来保存相同的 function instance


<<:  D6. 学习基础C、C++语言

>>:  Rules Engine 规则引擎

Day 04: 进入主题前的补充:SOLID

为什麽要补充? 当决定铁人赛的题目是 Design Patterns 时,除了先 Google 看看...

第33天~

这个得上一篇在https://ithelp.ithome.com.tw/articles/10257...

DAY29-ASP.NET网页切换导向及状态管理-趴水

ASP.NET网页切换导向及状态管理-趴水 今天来做做看 在网页输入资料後 按下按钮 可以将资料导向...

Day 3 设定 tsconfig.json 档

上一篇提到下了 tsc --init 指令之後会创建出一个 tsconfig.json 的档案,这个...

DAY 07 Mixins

混入 Mixins 当我们在编写 css 时,常常会发现有要重复套用的地方,像是一个网站的主题样式,...