React Hooks大全—useMemo

React Hooks有很多种,其中之一就是useMemo,它可以帮助我们优化组件的性能,避免不必要的渲染和计算。本文将介绍useMemo的基本使用,实现原理,最佳实践和一些常见的问题。

基本使用

公众号:Code程序人生,个人网站:https://creatorblog.cn

useMemo接受两个参数:一个创建函数和一个依赖数组。useMemo会返回创建函数的返回值,并且只有当依赖数组中的某个值发生变化时,才会重新执行创建函数。useMemo的基本语法如下:

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

上面的代码中,useMemo会返回computeExpensiveValue(a, b)的结果,并且只有当ab发生变化时,才会重新调用computeExpensiveValue(a, b)。这样可以避免在每次渲染时都执行computeExpensiveValue(a, b),从而提高性能。

useMemo的一个典型的应用场景是,当我们有一个复杂的组件,它接受一个对象作为props,而这个对象是由父组件通过一些计算得到的,我们可以使用useMemo来缓存这个对象,避免在每次父组件渲染时都重新创建这个对象,导致子组件也重新渲染。例如:

// 父组件
function Parent({ a, b }) {
  // 使用useMemo来缓存data对象,只有当a或b变化时,才重新创建data对象
  const data = useMemo(() => ({ a, b }), [a, b]);
  return (
    <div>
      <p>a: {a}</p>
      <p>b: {b}</p>
      <Child data={data} />
    </div>
  );
}

// 子组件,使用React.memo来避免不必要的渲染
const Child = React.memo(({ data }) => {
  console.log("Child render");
  return <div>{JSON.stringify(data)}</div>;
});

上面的代码中,如果我们改变ab的值,父组件会重新渲染,同时也会重新创建data对象,导致子组件也重新渲染。但是如果我们改变其他的状态,比如父组件的cd,父组件会重新渲染,但是data对象不会变化,所以子组件不会重新渲染。这样可以提高子组件的性能,避免不必要的渲染。

实现原理

useMemo的实现原理其实很简单,它就是利用了闭包和缓存的机制,来保存上一次的创建函数和依赖数组,然后在每次渲染时,比较当前的依赖数组和上一次的依赖数组,如果有变化,就重新执行创建函数,否则就返回上一次的缓存值。下面是一个简单的useMemo的实现:

// 用一个全局变量来保存上一次的创建函数和依赖数组
let lastCreate;
let lastDeps;

function useMemo(create, deps) {
  // 如果没有传入依赖数组,或者依赖数组的长度不一致,就重新执行创建函数
  if (!lastDeps || lastDeps.length !== deps.length) {
    lastCreate = create;
    lastDeps = deps;
    return create();
  }
  // 否则,遍历依赖数组,比较每一项是否相等,如果有不相等的,就重新执行创建函数
  for (let i = 0; i < deps.length; i++) {
    if (lastDeps[i] !== deps[i]) {
      lastCreate = create;
      lastDeps = deps;
      return create();
    }
  }
  // 如果依赖数组都相等,就返回上一次的缓存值
  return lastCreate();
}

最佳实践

使用useMemo时,有一些最佳实践和注意事项,我们需要遵守和了解,以免出现错误或者性能问题。下面列举了一些常见的最佳实践:

  • 不要在useMemo中执行有副作用的操作,比如修改状态,发起请求,订阅事件等。useMemo不保证创建函数的执行时机,有可能会被React跳过或者延迟执行。如果需要执行有副作用的操作,应该使用useEffect或者useLayoutEffect。
  • 不要依赖useMemo来保证引用的稳定性,比如用useMemo来返回一个函数或者一个组件。useMemo不保证缓存值的永久有效性,有可能会被React在任何时候清除或者重置。如果需要保证引用的稳定性,应该使用useCallback或者useRef。
  • 不要过度使用useMemo,因为useMemo本身也有一定的开销,比如比较依赖数组,缓存值等。如果创建函数的执行代价不高,或者组件的渲染代价不高,或者组件的渲染频率不高,就没有必要使用useMemo。只有当我们确实遇到了性能问题,才需要使用useMemo来优化。
  • 不要忘记传入依赖数组,或者传入错误的依赖数组。如果不传入依赖数组,useMemo就会在每次渲染时都重新执行创建函数,失去了缓存的意义。如果传入错误的依赖数组,比如漏掉了某个依赖,或者传入了不相关的依赖,就会导致缓存值的不正确或者不必要的更新。我们应该尽量保证依赖数组的完整和准确,可以使用ESLint的react-hooks插件来帮助我们检查依赖数组。

总结

useMemo是一个非常有用的Hook,它可以帮助我们优化组件的性能,避免不必要的渲染和计算。

useMemo的基本用法是,传入一个创建函数和一个依赖数组,返回创建函数的返回值,并且只有当依赖数组中的某个值发生变化时,才会重新执行创建函数。

useMemo的实现原理是,利用闭包和缓存的机制,来保存上一次的创建函数和依赖数组,然后在每次渲染时,比较当前的依赖数组和上一次的依赖数组,如果有变化,就重新执行创建函数,否则就返回上一次的缓存值。

使用useMemo时,我们需要遵守一些最佳实践和注意事项,比如不要在useMemo中执行有副作用的操作,不要依赖useMemo来保证引用的稳定性,不要过度使用useMemo,不要忘记传入依赖数组,或者传入错误的依赖数组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CreatorRay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值