React Performance Hooks之useMemo

2023-10-30  本文已影响0人  米诺zuo

默认情况下,React 每次重新渲染时都会重新运行组件的整个主体。
优化重新渲染性能的常见方法是跳过不必要的工作。 例如,可以告诉 React 重用缓存的计算,或者如果数据自上次渲染以来没有更改,则跳过重新渲染。

要跳过计算和不必要的重新渲染,请使用以下 Hooks 之一:

useMemo

useMemo 会在重新渲染之间缓存calculateValue结果,直到dependencies发生变化,第二个参数不传的话,会每次都调用计算函数。

const cachedValue = useMemo(calculateValue, dependencies)

定义

参数

返回值

在初始渲染中,“useMemo”返回不带参数调用“calculateValue”的结果。

在下一次渲染期间,它将返回上次渲染中已存储的值(如果依赖项未更改),或者再次调用“calculateValue”,并返回“calculateValue”返回的结果。

用法

1.跳过重新计算

1.当 List 的 props 与上次渲染时相同时,可以通过将其包装在 memo:
中来告诉 List 跳过重新渲染:

import { useMemo, useState } from "react";

export function MemoDemo() {
  const [name, setName] = useState("Tom");
  const [todoList, setTodoList] = useState(["1", "2", "3"]);
  const todoData: any = useMemo(() => {
    return todoList.filter((item) => item != "1");
  }, [todoList]);

  return (
    <div>
      <div
        onClick={() => {
          setName("Lisa"); //click的时候, 不会在调用filter方法
        }}
      >
        memo {name}
      </div>
      <List todoList={todoData}></List>
    </div>
  );
}
function List({ todoList }) {
  return todoList.map((item) => <span key="item">{item}</span>);
}

2.记住另一个hook的依赖项

function Dropdown({ allItems, text }) {
  const searchOptions = { matchMode: 'whole-word', text };

  const visibleItems = useMemo(() => {
    return searchItems(allItems, searchOptions);
  }, [allItems, searchOptions]); // 🚩 注意: dependency是在组件中创建的object
  // ...

上述dependency是在组件中创建的object,每次组件在渲染的时候都会重新创建一个searchOption对象,每次都是不同的searchOptions对象, 所以visibleItems每次渲染都会执行。

如何解决这个问题?可以将searchOptions对象也通过useMemo存储下。

function Dropdown({ allItems, text }) {
  const searchOptions = useMemo(() => {
    return { matchMode: 'whole-word', text };
  }, [text]); // ✅ Only changes when text changes

  const visibleItems = useMemo(() => {
    return searchItems(allItems, searchOptions);
  }, [allItems, searchOptions]); // ✅ Only changes when allItems or searchOptions changes
  // ...

进一步的优化,可以将searchOptions对象放在useMemo计算方法内

function Dropdown({ allItems, text }) {
  const visibleItems = useMemo(() => {
    const searchOptions = { matchMode: 'whole-word', text };
    return searchItems(allItems, searchOptions);
  }, [allItems, text]); // ✅ Only changes when allItems or text changes
  // ...

3.缓存一个方法

export default function ProductPage({ productId, referrer }) {
  function handleSubmit(orderDetails) {
    post('/product/' + productId + '/buy', {
      referrer,
      orderDetails
    });
  }

  return <Form onSubmit={handleSubmit} />;
}

注意:{}, (){}, ()=> {},这种声明在重新渲染时, 会创建一个新的函数,那么对于缓存来说,会认为是不同的方法。
如何优化?

export default function Page({ productId, referrer }) {
  const handleSubmit = useMemo(() => {
    return (orderDetails) => {
      post('/product/' + productId + '/buy', {
        referrer,
        orderDetails
      });
    };
  }, [productId, referrer]);

  return <Form onSubmit={handleSubmit} />;
}

这样看着有些繁琐,进一步优化,使用useCallback

export default function Page({ productId, referrer }) {
  const handleSubmit = useCallback((orderDetails) => {
    post('/product/' + productId + '/buy', {
      referrer,
      orderDetails
    });
  }, [productId, referrer]);

  return <Form onSubmit={handleSubmit} />;
}

参考更多 useCallback.

好了,那我们的useMemo到这里就结束了。

宝子们可以收藏评论交流哦

上一篇 下一篇

猜你喜欢

热点阅读