React Memo

React.memo— это компонент высшего порядка (HOC), используемый для оптимизации производительности функциональных компонентов. Он повышает производительность за счёт мемоизации выходных данных рендеринга компонента и пропуска повторных рендеров, когда пропсы компонента не изменились. Ниже приводитсяReact.memoподробное введение и методы использования.

1. Базовое использование

React.memoОсновное использование — передать функциональный компонент в качестве аргумента вReact.memo, и вернуть мемоизированный компонент.

Пример

import React from 'react';
import ReactDOM from 'react-dom';

const MyComponent = React.memo((props) => {
  console.log('Rendering MyComponent');
  return <div>{props.text}</div>;
});

const App = () => {
  const [count, setCount] = React.useState(0);
  const [text, setText] = React.useState('Hello, world!');

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Увеличить счётчик</button>
      <MyComponent text={text} />
    </div>
  );
};

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

В этом примере, даже еслиcountсостояние изменяется,MyComponentон не будет повторно рендериться, потому что егоpropsне изменилось.

2. Использование пользовательской функции сравнения

По умолчанию,React.memoсравнивает только предыдущие и следующиеprops, и если изменений нет, он не будет повторно рендериться. Вы можете точнее управлять логикой повторного рендеринга, передав пользовательскую функцию сравнения.

Сигнатура пользовательской функции сравнения:

function areEqual(prevProps, nextProps) {
  // 返回 true 表示相等,不需要重新渲染
  // 返回 false 表示不相等,需要重新渲染
}

Пример

import React from 'react';
import ReactDOM from 'react-dom';

const MyComponent = React.memo((props) => {
  console.log('Rendering MyComponent');
  return <div>{props.text}</div>;
}, (prevProps, nextProps) => {
  return prevProps.text === nextProps.text;
});

const App = () => {
  const [count, setCount] = React.useState(0);
  const [text, setText] = React.useState('Hello, world!');

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Увеличить счётчик</button>
      <MyComponent text={text} />
    </div>
  );
};

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

В этом примере пользовательская функция сравнения проверяетtextизменилось ли оно. Еслиtextне изменилось,MyComponentон не будет повторно рендериться.

3. Практические сценарии применения

React.memoОн очень хорошо подходит для следующих сценариев:

  • Отображение статических данных: props, получаемые компонентомpropsредко меняются, но сам компонент относительно сложен, и повторный рендеринг обходится дорого.
  • Оптимизация производительности: В больших списках или таблицах каждый элемент является независимым компонентом, с помощьюReact.memoможно избежать ненужных повторных рендеров.
  • Избегайте глубоких проверок равенства: пользовательская функция сравнения позволяет избежать глубоких проверок равенства, особенно когдаpropsсодержит большой объем данных.

4. Примечания

  • Поверхностное сравнение: По умолчанию,React.memoвыполняет поверхностное сравнение, то есть сравнивает толькоpropsсодержимое верхнего уровня. Вложенные объекты требуют пользовательской функции сравнения.
  • Состояние и контекст:React.memoучитывает толькоpropsизменения. Изменения внутреннего состояния компонента и контекста не будут вызывать повторный рендеринг.

5. С помощьюuseMemoиuseCallbackразница

  • React.memo: используется для мемоизации всего компонента и оптимизации рендеринга компонента.
  • useMemo: используется для мемоизации значений или вычисленных результатов внутри функциональных компонентов.
  • useCallback: используется для мемоизации функций обратного вызова внутри функциональных компонентов, чтобы избежать ненужного повторного создания.

Пример

import React, { useState, useMemo, useCallback } from 'react';
import ReactDOM from 'react-dom';

const ChildComponent = React.memo(({ onClick, count }) => {
  console.log('Rendering ChildComponent');
  return <button onClick={onClick}>Count: {count}</button>;
});

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

  const increment = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  const doubledCount = useMemo(() => count * 2, [count]);

  return (
    <div>
      <p>Удвоенное количество: {doubledCount}</p>
      <ChildComponent onClick={increment} count={count} />
    </div>
  );
};

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

В этом примере,useCallbackиuseMemoиспользуется для оптимизации функций и вычисляемых результатов,React.memoиспользуется для оптимизации рендеринга дочерних компонентов.

Итог

React.memo— мощный инструмент, который может эффективно повысить производительность функциональных компонентов и избежать ненужных повторных рендеров. ИспользуяReact.memoи пользовательские функции сравнения, вы можете значительно оптимизировать производительность приложения, не влияя на логику приложения.

Другие расширения