面试官:说一下你对 useMemo 和 React.memo 的理解

前言

React 中的这两个函数都带有 memo,看着比较相似,但是作用和使用场景却不一致。

memo 的英文含义为备忘录,可以理解为保存,记忆之类,从字面意思可以猜测到它的作用。

可能没有实战的童鞋还容易把这两个搞混,但是这两个函数有着完全不一样的功能,也不需要拿来比较,千万不要搞混了,今天就带大家一起来详细的分析一下这两个函数的作用和使用场景!

useMemo

useMemo 是 React 中用来进行性能优化的钩子函数之一,它的作用是用来缓存计算结果,只有在依赖项发生变化时才重新计算,可以有效减少不必要的计算开销。常见的使用场景是在需要进行大量计算或者复杂逻辑的组件中,通过 useMemo 缓存计算结果,避免不必要的重复计算,可以提高组件的性能。

当点击按钮时,count 会加1,而使用 useMemo 则会监听到依赖项的变化,此时会计算得到doubledCount,熟悉 Vue 的小伙伴应该会知道,和 computed 相似。

js 复制代码
import React, { useState, useMemo } from 'react';

const App = () => {
  const [count, setCount] = useState(0);

  // 通过 useMemo 缓存计算结果
  const doubledCount = useMemo(() => {
    return count * 2;
  }, [count]);


  return (
    <div>
      <h1>useMemo Example</h1>
      <p>Count: {count}</p>
      <p>Doubled Count: {doubledCount}</p>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
    </div>
  );
};

export default App;

React.memo

使用 React的小伙伴都了解,当组件中的 state 数据发生变化时,会重新渲染该组件,如果引入子组件,子组件也会重新渲染,这会造成不必要的开销。React.memo 则是用来解决这个问题的。

作用

React.memo 会浅比较当前组件的 props 与上一次渲染时的 props。如果 props 没有变化,则跳过渲染过程。

在这个案例中,我们有两个点击事件,其中点击 handleChangeCount 会引起 count 的改变,当 count 改变时,会引起组件重新渲染,在组件中引入了子组件 MyComponent ,默认情况下 MyComponent 也会重新渲染。

很明显我们可以发现,MyComponent 里面并没有用到 count,也就是说 MyComponent 组件并不需要重新渲染,MyComponent 只需要在自己依赖的 props 改变时重新渲染,所以我们使用 React.memo 进行包裹,包裹之后只会在 props 发生变化时重新渲染 MyComponent 组件 。

js 复制代码
import React, { useState } from 'react';

// 一个纯函数组件
const MyComponent = React.memo(({ name, age }) => {
  console.log('MyComponent rendered');
  return (
    <div>
      <h2>{name}</h2>
      <p>Age: {age}</p>
    </div>
  );
});

const App = () => {
  const [person, setPerson] = useState({ name: 'John', age: 30 });
  const [count, setCount] = useState(0);

  const handleChangeAge = () => {
    setPerson({ ...person, age: person.age + 1 });
  };

  const handleChangeCount = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <MyComponent name={person.name} age={person.age} />
      <button onClick={handleChangeAge}>Change Age</button>
      <button onClick={handleChangeCount}>Change Count</button>
      <p>Count: {count}</p>
    </div>
  );
};

export default App;

通过使用 React.memo,我们避免了 MyComponent 在不必要的情况下重新渲染,从而提高了性能。

需要注意的是,React.memo 只会对函数组件进行浅层比较。如果 props 是一个引用类型(如对象或数组),即使属性值没有改变,React 也会认为它是一个新的引用,从而导致组件重新渲染。在这种情况下,可以使用 React.memo 的第二个参数来提供一个自定义的比较函数。

通过自定义第二个参数,拿到前一个跟后一个 props,从而比较里面的属性值是否发生变化而决定是否重新渲染组件。

js 复制代码
import React from 'react';

const Person = React.memo(({ person }) => {
  console.log('Person component rendered');
  return (
    <div>
      <h2>{person.name}</h2>
      <p>Age: {person.age}</p>
    </div>
  );
}, (prevProps, nextProps) => {
  // 自定义比较函数
  const prevPerson = prevProps.person;
  const nextPerson = nextProps.person;

  // 比较 person 对象的属性值
  return (
    prevPerson.name === nextPerson.name &&
    prevPerson.age === nextPerson.age
  );
});

const App = () => {
  const [person, setPerson] = React.useState({ name: 'John', age: 30 });

  const handleChangeAge = () => {
    setPerson({ ...person, age: person.age + 1 });
  };

  return (
    <div>
      <Person person={person} />
      <button onClick={handleChangeAge}>Change Age</button>
    </div>
  );
};

export default App;
相关推荐
敲敲了个代码3 小时前
从硬编码到 Schema 推断:前端表单开发的工程化转型
前端·javascript·vue.js·学习·面试·职场和发展·前端框架
dly_blog5 小时前
Vue 响应式陷阱与解决方案(第19节)
前端·javascript·vue.js
消失的旧时光-19435 小时前
401 自动刷新 Token 的完整架构设计(Dio 实战版)
开发语言·前端·javascript
console.log('npc')5 小时前
Table,vue3在父组件调用子组件columns列的方法展示弹窗文件预览效果
前端·javascript·vue.js
用户47949283569155 小时前
React Hooks 的“天条”:为啥绝对不能写在 if 语句里?
前端·react.js
我命由我123456 小时前
SVG - SVG 引入(SVG 概述、SVG 基本使用、SVG 使用 CSS、SVG 使用 JavaScript、SVG 实例实操)
开发语言·前端·javascript·css·学习·ecmascript·学习方法
用户47949283569156 小时前
给客户做私有化部署,我是如何优雅搞定 NPM 依赖管理的?
前端·后端·程序员
C_心欲无痕6 小时前
vue3 - markRaw标记为非响应式对象
前端·javascript·vue.js
qingyun9897 小时前
深度优先遍历:JavaScript递归查找树形数据结构中的节点标签
前端·javascript·数据结构
胡楚昊7 小时前
NSSCTF动调题包通关
开发语言·javascript·算法