美文网首页
React Performance Hooks之useMemo

React Performance Hooks之useMemo

作者: 米诺zuo | 来源:发表于2023-10-30 14:19 被阅读0次

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

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

    • useMemo 缓存计算结果。
    • useCallback缓存函数定义,再传递给优化组件。
      要优先考虑渲染,请使用以下 Hooks 之一:
    • useTransition 将状态转换标记为非阻塞并允许其他更新中断它。
    • useDeferredValue 可以推迟更新 UI 的非关键部分,并让其他部分先更新。

    useMemo

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

    const cachedValue = useMemo(calculateValue, dependencies)
    

    定义

    参数

    • calculateValue: 不带任何参数,例如 () =>,并返回想要计算的值。dependencies如果改变,会重新调用该函数。

    • dependencies: 依赖项列表,包括组件中计算中使用的每个值。例如:[todos, tab](通过 Object.is比较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到这里就结束了。

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

    相关文章

      网友评论

          本文标题:React Performance Hooks之useMemo

          本文链接:https://www.haomeiwen.com/subject/xgpbidtx.html