React.memo() 是你的朋友

2025-06-07

React.memo() 是你的朋友

React.memo()是每个 React 开发者必备的工具之一。它使我们能够记忆 React 组件。与任何工具一样,在深入研究如何使用之前React.memo(),我们先来了解一下问题所在。

为什么要进行记忆?

记忆化是一个通用概念,其基本含义是缓存某种计算的结果以供后续使用。它是一种在编程领域广泛使用的优化技术。

要记住的一点是,无论何时使用记忆法,都必须有一个标准来规定缓存的结果何时不再有效并且必须重新进行计算。

为了理解这解决的问题,请考虑以下 React 组件:

import { useState, Fragment } from "react";

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

  function handleDecrement() {
    setCount((oldCount) => --oldCount);
  }

  function handleIncrement() {
    setCount((oldCount) => ++oldCount);
  }

  return (
    <Fragment>
      <p>Count is {count}</p>
      <button onClick={handleDecrement}>-</button>
      <button onClick={handleIncrement}>+</button>
    </Fragment>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

一个简单的组件,可以保持计数的增加或减少。

1

现在让我们向 中添加另一个组件<App />。为了简单起见,我们将创建一个组件,该组件根据传递给它的 prop 的<Message />返回某种消息。msgId

function Message(props) {
  let msg = "hello, world";

  if (props.msgId === 1) {
    msg = "hey there!";
  } else if (props.msgId === 2) {
    msg = "hola!";
  }

  return <p>{msg}</p>;
}
Enter fullscreen mode Exit fullscreen mode

我们在这里尽量保持简单,但想象一下,这个<Message />组件需要进行一些繁重的计算,或者可能需要向外部 API 发送请求才能获取最终消息。我们将通过添加大家喜欢的console.log()组件来模拟这种情况。

function Message(props) {
  let msg = "hello, world";

  console.log("Just performed some seriously heavy computation");

  if (props.msgId === 1) {
    msg = "hey there!";
  } else if (props.msgId === 2) {
    msg = "hola!";
  }

  return <p>{msg}</p>;
}
Enter fullscreen mode Exit fullscreen mode

让我们更新<App />组件以使用<Message />

import { useState, Fragment } from "react";

function Message(props) {
  let msg = "hello, world";

  console.log("Just performed some seriously heavy computation");

  if (props.msgId === 1) {
    msg = "hey there!";
  } else if (props.msgId === 2) {
    msg = "hola!";
  }

  return <p>{msg}</p>;
}

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

  function handleDecrement() {
    setCount((oldCount) => --oldCount);
  }

  function handleIncrement() {
    setCount((oldCount) => ++oldCount);
  }

  return (
    <Fragment>
      <Message msgId={1} />
      <p>Count is {count}</p>
      <button onClick={handleDecrement}>-</button>
      <button onClick={handleIncrement}>+</button>
    </Fragment>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

在下面的视频中,请特别注意每次count改变时间时都会进行大量计算。

2

要了解为什么每次更改时都要进行大量计算count,请查看此文章:React 中的重新渲染

此时,退一步想想我们的 UI 此刻是多么低效。count虽然没有<Message />任何影响,但每次count更新时,仍然需要进行大量计算。我们只希望在更改时进行计算,msgId因为更改msgId应该导致不同的消息。

React.memo() 来帮忙

React.memo()是一个高阶组件。它接受一个组件作为参数,并记录其结果。只有当原始组件的 props 发生变化时,记录的结果才会更新。

要使用React.memo(),只需将组件作为参数传递并保存结果即可。我们的<Message />组件将变为:

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

const Message = memo(function (props) {
  let msg = "hello, world";

  console.log("Just performed some seriously heavy computation");

  if (props.msgId === 1) {
    msg = "hey there!";
  } else if (props.msgId === 2) {
    msg = "hola!";
  }

  return <p>{msg}</p>;
});
Enter fullscreen mode Exit fullscreen mode

注意:我memo()这里只导入了。如果你已经React导入了,你可以使用React.memo()而不是memo()

现在我们的代码如下所示:

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

const Message = memo(function (props) {
  let msg = "hello, world";

  console.log("Just performed some seriously heavy computation");

  if (props.msgId === 1) {
    msg = "hey there!";
  } else if (props.msgId === 2) {
    msg = "hola!";
  }

  return <p>{msg}</p>;
});

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

  function handleDecrement() {
    setCount((oldCount) => --oldCount);
  }

  function handleIncrement() {
    setCount((oldCount) => ++oldCount);
  }

  return (
    <Fragment>
      <Message msgId={1} />
      <p>Count is {count}</p>
      <button onClick={handleDecrement}>-</button>
      <button onClick={handleIncrement}>+</button>
    </Fragment>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

这次,请注意,当应用程序刷新时计算已经完成,但更改count不再具有该结果。

3


👉🏻 订阅我的新闻通讯:点击此处

👉🏻 在 Twitter 上关注我:点击此处


文章来源:https://dev.to/therealnrf/reactmemo-is-your-friend-e6p
PREV
学习编程的 5 个重要策略
NEXT
成为一名全栈 Web 开发人员有点疯狂