likes
comments
collection
share

React中的hook之useMemo

作者站长头像
站长
· 阅读数 57

1.useMemo介绍

众所周知,react中的useMemouseCallback与组件的性能优化有关,useMemo与状态hookuseState不同,需要着重的介绍其实现逻辑,理解之后才能用在更加合适的地方,即-最佳实践.其性能优化主要在下面这几方面:

  • 跳过代价昂贵的重新计算
  • 跳过组件的重新渲染
  • 记忆另一个 Hook 的依赖

2.何时使用useMemo

react项目中,所有需要性能优化的地方,当开发大型项目时,在不过高提升开发者心智负担的同时,尽可能多使用useMemo来进行饱和时开发..

3.useMemo使用方法

const cachedValue = useMemo(calculateValue, dependencies)

当我们使用useMemo时,接受两个参数:

1.要缓存计算值的函数 纯函数,返回结果为cachedValue

2.函数计算的依赖值 数组,组件每次渲染时,检查dependencies是否变化,若无变化,则不计算

举例说明:

(1).跳过代价昂贵的重新计算:

在前后端分离的开发模式下,我们一般认为数据计算,分析应该交给服务端,我们只需要调取api获取数据来完成组件的渲染,但某些特殊情况下,通过客户端的计算来达到开发目的,比通过服务端计算得到数据更加快速,安全,用户体验更好,所以现在讨论通过客户端计算的例子:

比如count是从服务端获取的数据,我们需要除掉数组中不是x倍数的数字,很轻松可以完成

//count :[1,2,3,4,5,6,7,8,9,10]

console.log(count.filter((item) => item % x === 0))

但是当countlength很大,客户端的计算将很昂贵,例如:

import {  useState } from "react";

let count = [];

const Test = () => {
  const [data, setData] = useState(1);
  
  for (let i = 0; i < 10000000; i++) {
    count.push(i);
  }
  function handChange() {
    setData(2);
  }
  console.log(count);
  return (
    <div onClick={handChange}>{data}</div>
  );
};
export default Test;

当我们点击屏幕时,触发handChange方法,更改data,页面重新渲染,将重新执行for循环来更新count数组,此时能明显的感受到,页面加载极慢,此时useMemo就可以发挥出他的作用:

import { useMemo, useState } from "react";

let count = [];

const Test = () => {
  const [data, setData] = useState(1);

  count = useMemo(() => {
    let newCount = [];
    for (let i = 0; i < 10000000; i++) {
      newCount.push(i);
    }
    return newCount;
  }, []);
  console.log(count);

  function handChange() {
    setData(2);
  }
  return <div onClick={handChange}>{data}</div>;
};
export default Test;

当我们查看count的打印时间,可以明显的体现···

(2).跳过组件的重新渲染:

与跳过代价昂贵的重新计算不同,页面渲染是发生在js计算之后的.. 所有学过react的同学都知道,react的性能较强得益于他自身的虚拟DOM(diff算法):

当组件重新渲染时,会从当前的根目录开始做深度优先遍历,生成虚拟DOM,两个虚拟DOM相比较,如果没有改变,则不重新生成DOM树,否则更新虚拟DOM树并更新真实DOM..

useMemo的作用是直接跳过渲染,当外层组件重新渲染时,深度遍历到useMemo作用下的组件时,直接跳过,不进行后续过程(diff算法)的计算..

以下方代码为例,每次点击页面,data值增加1,并且会打印出count,因为组件Card每次都会重新渲染,触发js执行,再生成虚拟DOM,比较后发现虚拟DOM相同,不再渲染页面

import { useState } from "react";
const Test = () => {
  const [data, setData] = useState(1);
  const count = { name: "小明", age: 18 };
  function handChange() {
    setData(() => data + 1);
  }
  return (
    <div onClick={handChange}>
      {data}
      <Card count={count} />
    </div>
  );
};
export default Test;

const Card = ({ count }) => {
  console.log(count);
  return <div>{count.name}</div>;
};

而useMemo提供了更好的交互方式,当组件得知,定义的依赖没有发生变化,表示页面操作与自身组件没有关系时,不再生产虚拟DOM从组件根目录对比 ,而是直接跳过,例子如下

import { memo, useMemo, useState } from "react";
const Test = ({text}) => {
  const [data, setData] = useState(1);

  const count = useMemo(() => {
    return { name: "小明", age: 18 };
  }, [text]);
  function handChange() {
    setData(() => data + 1);
  }
  return (
    <div onClick={handChange}>
      {data}
      <Card count={count} />
    </div>
  );
};
export default Test;

const Card = memo(({ count }) => {
  console.log(count);
  return <div>{count.name}</div>;
});

(3).记忆另一个 Hook 的依赖:

useMemo的依赖,一般为父组件传来的props,当props发生变化,才会重新渲染,但如果我们不仅仅想使用props,则在useMemo定义依赖,否则每次组件重新渲染,定义的引用数据类型将重新创建并赋予新的指针,依赖将自动改变,代码如下:

import { memo, useMemo, useState } from "react";

const Test = ({text}) => {
  const [data, setData] = useState(1);
  //const person={sex:'男',text:text } //错误定义依赖,Test渲染时person改变,每次点击都将打印
  
  const person = useMemo(() => { 
  return { sex: '男', text };  }, 
  [text]);   //正确定义依赖,记忆另一个useMemo的依赖
  
  const count = useMemo(() => {
    return { name: "小明", age: 18 };
  }, [person]);
  
  function handChange() {
    setData(() => data + 1);
  }
  return (
    <div onClick={handChange}>
      {data}
      <Card count={count} />
    </div>
  );
};
export default Test;

const Card = memo(({ count }) => {
  console.log(count);
  return <div>{count.name}</div>;
});

4.useMemo总结

useMemo与其他hook不同,不属于业务hook,属于优化hook,当我们整个react项目都不使用useMemo,也不会影响正常的组件运行,反而,如果不当的使用,不仅仅会增加开发者的心智负担,也可能使项目的优化结果不尽人意..

但是,只有掌握了useMemo的使用时机和使用方法,才能更上一层楼,使得项目以最佳状态运行,学习useMemo重要的是理解,加油,少年!

转载自:https://juejin.cn/post/7281210797959725067
评论
请登录