Использование useMemo вместо проблемы с синтаксисом React.memo

Мне нужно сделать демонстрацию использования React Hooks useMemo. У меня есть рабочий код, который делает то, что я хочу:

const SpeakerCardDetail = React.memo(
  ({id,...

Я нашел связь, который показывает, что я мог бы использовать синтаксис, похожий на этот, но я не могу точно понять это.

Это насколько я понял:

const SpeakerDetail = React.useMemo(() => {
   ({ id,

Хотя явно не то. Я понимаю, что React.memo решает проблему, но мне нужно показать useMemo в действии, и я надеюсь, что есть альтернативный синтаксис, который я могу использовать.

Подожди, что тебе нужно сделать? просто любой пример использования useMemo ?

azium 02.04.2019 05:27
React.memo позволяет функциональному компоненту иметь ту же оптимизацию, что и PureComponent для компонентов на основе классов. useMemo предназначен для запоминания вызовов функций внутри функционального компонента. Заменить один на другой будет сложно, так как у них разное назначение.
skyboyer 02.04.2019 05:30

Я надеюсь, что смогу получить тот же результат, что и React.memo, то есть возврат чистой функции сохраняется с мемоизацией.

Pete 02.04.2019 06:04
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
42
3
18 784
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

React.memo и React.useMemo вообще не эквивалентны (не полагайтесь на сходство имен). Вот цитата из React.memoдокумент:

React.memo is a higher order component.

Таким образом, это HOC, который может оптимизировать воспроизведение вашего компонента, учитывая, что он отображает тот же результат с теми же свойствами.

React.useMemo, с другой стороны, более общий и возвращает запомненное значение:

Pass a “create” function and an array of dependencies. useMemo will only recompute the memoized value when one of the dependencies (either a or b) has changed.

const memoizedValue = useMemo(
  () => computeExpensiveValue(a, b), 
  [a, b]
);

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

И есть еще такое предупреждение:

In the future, React may choose to “forget” some previously memoized values and recalculate them on next render, e.g. to free memory for offscreen components. Write your code so that it still works without useMemo — and then add it to optimize performance.

Спасибо. Я пришел к такому же выводу и был обманут именованием. Сейчас я использую в качестве примера результаты сортировки перед рендерингом.

Pete 02.04.2019 07:12

Хотя, должен сказать, я долго смотрел на этот пример, потому что он заставляет их чувствовать себя примерно одинаково. codeandbox.io/s/7m03xn9wlx

Pete 02.04.2019 07:13

Хотя memo — HOC, а useMemo — хук, вы можете использовать их для достижения того же результата.

Для контекста, HOC — это более старый шаблон React, который много лет использовался как с классовыми, так и с функциональными компонентами. Вы все еще можете использовать его сегодня (плана прекращения поддержки нет).

Хуки — это относительно новая концепция (около года), которая расширяет функциональные компоненты и во многих случаях резко упрощает код. Вот почему многие разработчики переходят на использование хуков.

В любом случае, и memo, и useMemo принимают два аргумента: функцию и реквизит. Если ни один из реквизитов не изменится при последующих повторных рендерингах, функция не будет выполняться снова, а вместо этого вернет предыдущий результат. Фактически это заменяет обратные вызовы shouldComponentUpdate чисто функциональным подходом.

С memo ваш код будет выглядеть так:

const SpeakerCardDetail = React.memo(
  (props) => <div>{props.name}</div>
)

С useMemo вы бы написали:

const SpeakerCardDetail = (props) => useMemo(() => <div>{props.name}</div>)

Обратите внимание, что useMemo используется внутри функции вашего компонента, а memo оборачивает функцию.

Традиционно useMemo можно записать так:

function SpeakerCardDetail(props) {
  return useMemo(
    () => <div>{props.name}</div>
  )
}

Теперь приведенный выше код будет перерисовываться каждый раз, что делает функцию useMemo немного бесполезной. Чтобы заставить его работать, нам нужно добавить второй аргумент. (memo по-прежнему работает даже без указания второго аргумента, но вы можете добавить его, чтобы настроить)

Есть небольшая разница в формате второго аргумента. memo ожидает функцию, которая сравнивает предыдущие и текущие реквизиты, точно так же, как shouldComponentUpdate делает это для компонентов класса.

const SpeakerCardDetail = React.memo(
  (props) => <div>{props.name}</div>
,
  // return true if passing nextProps to render would return the same result as passing prevProps to render, otherwise return false
  (prevProps, nextProps) => prevProps.name === nextProps.name
)

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

function SpeakerCardDetail(props) {
  return useMemo(
    () => <div>{props.name}</div>
  ,
    [props.name]
  )
}

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

Не могли бы вы предложить нам, что лучше, чтобы мы могли использовать оба подхода?

Muhammad 27.04.2020 15:58

@Muhammad Ни один из них строго не лучше другого. Если вы используете компоненты класса, вы должны использовать memo. Если вы используете функциональные компоненты с хуками, вы можете использовать useMemo (хотя в этом случае вы также можете использовать memo). useMemo также имеет более краткий второй аргумент. В конце концов, это всего лишь вопрос предпочтений. Любая разница в производительности должна быть незначительной.

Petr Bela 28.04.2020 17:13

Когда компонент находится внутри условия, с useMemo вы получаете меньше хуков, чем ожидалось, поэтому в этом случае я полагаю, что memo — единственный вариант.

Goran Jakovljevic 29.04.2020 07:53

Суть в том, что если вам удобно использовать хуки и вы используете их в своем проекте, вы можете предпочесть useMemo для «согласованности». Хотя, как отмечает @GoranJakovljevic, применяются обычные правила хуков, поэтому вы всегда можете вернуться к React.memo. Если вы не используете хуки, всегда используйте React.memo.

Petr Bela 29.04.2020 18:14

Подводя итог React.memo против useMemo / TLDR:

React.memo — это компонент более высокого порядка (HOC для краткости), который запоминает компонент реакции на основе свойств.

export function SomeComponent({ num }) {
  return <p>{num * 10}</p>
}

export default React.memo(SomeComponent, function areEqual(
  prevProps,
  nextProps
) {
  if (prevProps.num !== nextProps.num) {
    return false
  }
  return true
})

useMemo — это хук реакции, который запоминает значение, возвращаемое функцией, которую вы ему предоставляете.

export function SomeComponent({ num }) {
  const res = useMemo(() => num * 10, [num])
  return <p>{res}</p>
}

Источник

React.Memo

Использование React.memo заставит React пропустить рендеринг компонента, если его свойства не изменились.

Пример:

const Child = React.memo(props => {
  console.info("rendered");
  return <React.Fragment>{props.name}</React.Fragment>;
});

class App extends React.Component {
  state = {
    value: 1,
    name: "Jioke"
  };

  handleClick = () => {
    this.setState({
      value: this.state.value + 1
    });
  };

  render() {
    return (
      <React.Fragment>
        <Child name = {this.state.name} />
        <div>{this.state.value}</div>
        <button onClick = {this.handleClick}>+</button>
      </React.Fragment>
    );
  }
}

Когда мы нажимаем кнопку, Child Компонент не перерисовывается (rendered отображается только 1)

Примечания: Чем больше реквизитов, тем больше вычислений, сравнения (проверка рендеринга или нет) добавленная стоимость сравнения не стоит того для «простого» компонента с точки зрения затрат рендеринга, согласования, изменения DOM и побочных эффектов. Так что будьте осторожны, чтобы решить, использовать его или нет

UseMemo

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

Пример:

import { useState, useMemo } from "react";
import ReactDOM from "react-dom";

const App = () => {
  const [count, setCount] = useState(0);
  const [todos, setTodos] = useState([]);
  const calculation = useMemo(() => expensiveCalculation(count), [count]);

  const increment = () => {
    setCount((c) => c + 1);
  };
  const addTodo = () => {
    setTodos((t) => [...t, "New Todo"]);
  };

  return (
    <div>
      <div>
        <h2>My Todos</h2>
        {todos.map((todo, index) => {
          return <p key = {index}>{todo}</p>;
        })}
        <button onClick = {addTodo}>Add Todo</button>
      </div>
      <hr />
      <div>
        Count: {count}
        <button onClick = {increment}>+</button>
        <h2>Expensive Calculation</h2>
        {calculation}
      </div>
    </div>
  );
};

const expensiveCalculation = (num) => {
  console.info("Calculating...");
  for (let i = 0; i < 1000000000; i++) {
    num += 1;
  }
  return num;
};

ReactDOM.render(<App />, document.getElementById('root'));

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

Другие вопросы по теме