面试官:说一下你对 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;
相关推荐
Anlici4 分钟前
面试官:想把你问趴下 => 面题整理[3] 😮‍💨初心未变🚀
javascript·面试·前端框架
思茂信息7 分钟前
CST直角反射器 --- 距离多普勒(RD图), 毫米波汽车雷达ADAS
前端·人工智能·5g·汽车·无人机·软件工程
星星不打輰12 分钟前
Vue入门常见指令
前端·javascript·vue.js
好_快43 分钟前
Lodash源码阅读-isNative
前端·javascript·源码阅读
好_快1 小时前
Lodash源码阅读-reIsNative
前端·javascript·源码阅读
好_快1 小时前
Lodash源码阅读-baseIsNative
前端·javascript·源码阅读
好_快1 小时前
Lodash源码阅读-toSource
前端·javascript·源码阅读
aerror1 小时前
VsCode/Cursor workbench.desktop.main.js 的入口
javascript·ide·vscode
Oneforlove_twoforjob1 小时前
volta node npm yarn下载安装
前端·npm·node.js
咖啡の猫1 小时前
npm与包
前端·npm·node.js