React Memo

如果组件的 props 没有更改,使用 memo 将导致 React 跳过渲染组件,可以提高性能。

React.memo() 是一个高阶函数,它与 React.PureComponent 类似,但是一个函数组件而非一个类。

本节使用 React Hook 钩子。有关 Hook 的更多信息,请参见 React Hooks 部分。

问题

在本例中,即使 todos 没有更改,Todos 组件也会重新渲染。

实例:

index.js:

  1. import { useState } from "react";
  2. import ReactDOM from "react-dom";
  3. import Todos from "./Todos";
  4. const App = () => {
  5. const [count, setCount] = useState(0);
  6. const [todos, setTodos] = useState(["todo 1", "todo 2"]);
  7. const increment = () => {
  8. setCount((c) => c + 1);
  9. };
  10. return (
  11. <>
  12. <Todos todos={todos} />
  13. <hr />
  14. <div>
  15. Count: {count}
  16. <button onClick={increment}>+</button>
  17. </div>
  18. </>
  19. );
  20. };
  21. ReactDOM.render(<App />, document.getElementById('root'));

Todos.js:

  1. import { useState } from "react";
  2. import ReactDOM from "react-dom";
  3. import Todos from "./Todos";
  4. const App = () => {
  5. const [count, setCount] = useState(0);
  6. const [todos, setTodos] = useState(["todo 1", "todo 2"]);
  7. const increment = () => {
  8. setCount((c) => c + 1);
  9. };
  10. return (
  11. <>
  12. <Todos todos={todos} />
  13. <hr />
  14. <div>
  15. Count: {count}
  16. <button onClick={increment}>+</button>
  17. </div>
  18. </>
  19. );
  20. };
  21. ReactDOM.render(<App />, document.getElementById('root'));

单击 "increment" 按钮时,Todos 组件将重新渲染。如果此组件比较复杂,则可能会导致性能问题。


解决方法

要解决此问题,我们可以使用 memo

使用 memo 可防止 Todos 组件不必要地重新渲染。

Todos 组件导出装在 memo 中:

实例:

index.js:

  1. import { useState } from "react";
  2. import ReactDOM from "react-dom";
  3. import Todos from "./Todos";
  4. const App = () => {
  5. const [count, setCount] = useState(0);
  6. const [todos, setTodos] = useState(["todo 1", "todo 2"]);
  7. const increment = () => {
  8. setCount((c) => c + 1);
  9. };
  10. return (
  11. <>
  12. <Todos todos={todos} />
  13. <hr />
  14. <div>
  15. Count: {count}
  16. <button onClick={increment}>+</button>
  17. </div>
  18. </>
  19. );
  20. };
  21. ReactDOM.render(<App />, document.getElementById('root'));

Todos.js:

  1. import { useState } from "react";
  2. import ReactDOM from "react-dom";
  3. import Todos from "./Todos";
  4. const App = () => {
  5. const [count, setCount] = useState(0);
  6. const [todos, setTodos] = useState(["todo 1", "todo 2"]);
  7. const increment = () => {
  8. setCount((c) => c + 1);
  9. };
  10. return (
  11. <>
  12. <Todos todos={todos} />
  13. <hr />
  14. <div>
  15. Count: {count}
  16. <button onClick={increment}>+</button>
  17. </div>
  18. </>
  19. );
  20. };
  21. ReactDOM.render(<App />, document.getElementById('root'));

现在,TODO 组件仅在通过 Props 传递给它的 TODO 更新时重新渲染。