Когда нужно использовать мемоизацию

Ответ

Мемоизацию стоит применять, когда есть дорогостоящие вычисления или рендеринг компонентов, которые зависят от одних и тех же пропсов. Чаще всего это:

  1. Чистые функции с тяжелыми вычислениями
  2. Компоненты, которые часто ререндерятся с одинаковыми пропсами
  3. Оптимизация производительности при работе с большими списками

Пример с React.memo:

const ExpensiveComponent = React.memo(({ data }) => {
  // Тяжелые вычисления
  const result = heavyCalculation(data);
  return <div>{result}</div>;
});

Пример с useMemo:

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

Но не стоит мемоизировать всё подряд - это добавляет overhead по памяти и может дать обратный эффект. Оптимизируйте только реальные узкие места.

Ответ 18+ 🔞

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

Представь себе, блядь, повара на кухне. Есть у него фирменный соус «Тартар», который готовится из пятнадцати ингредиентов, и хуярит он его минут двадцать. И вот к нему каждые пять секунд заходят официанты: «Соус!», «Соус!», «Соус!». Он, бедолага, на каждый заказ начинает с нуля: яйца, масло, горчица, корнишоны, лук, ёпта... Заебётся же, сука! Вот тут ему и нужно мемоизировать этот соус. Приготовил один раз, поставил в холодильник (в кеш, блядь), и на следующие заказы просто отгружает готовую порцию. Красота.

А теперь представь другого повара — он делает бутерброд с маслом. Намазал и готово. И к нему тоже: «Бутер!», «Бутер!». Да ему проще новый сделать за две секунды, чем идти к холодильнику, открывать его, искать там этот бутер, доставать... Overhead, ёпта! Нахуя его мемоизировать? Только память засрёшь и усложнишь всё.

Так когда же, блядь, нужно мемоизировать?

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

    // Вот ЭТО надо мемоизировать, ибо heavyCalculation — это пиздец как долго.
    const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
  2. Компоненты, которые рендерятся чаще, чем пукан у ипохондрика, и всегда с одними и теми же пропсами. Вот смотри: есть у тебя список из тысячи пользователей, и каждый — отдельный UserCard. Если родительский компонент перерисовывается, то все тысяча карточек тоже попрут делать ре-рендер. А если в них тяжёлая вёрстка или логика? Пиздец. Вот тут оборачиваешь UserCard в React.memo, и он будет пересобираться только если реально изменились его пропсы (имя, аватарка).

    // Вот так. Теперь этот компонент не будет зря дергаться.
    const UserCard = React.memo(({ user }) => {
      return <div className="fancy-card">{user.name}</div>;
    });
  3. Когда ты передаёшь в дочерние компоненты объекты или функции, созданные на лету в родителе. Это, блядь, классика. Без useMemo и useCallback твой React.memo на дочернем компоненте — просто бесполезная хуйня, потому что ссылка на пропс будет каждый раз новая.

А когда НЕ НАДО, сука?

Да когда вычисления стоят три копейки! Не надо оборачивать в useMemo конкатенацию двух строк или сложение a + b. Не надо React.memo пихать на кнопку или заголовок. Ты только добавишь работу: сначала сравнение старых и новых пропсов, потом ещё доступ к кешу. Итог: вместо оптимизации получишь деградацию, ядрёна вошь.

Короче, правило простое: оптимизируй только реальные узкие места, которые нашёл в профайлере. Не гадай на кофейной гуще. Сначала напиши работающий код, потом замерь производительность, и если увидел, что какой-то компонент или вычисление — реальная пробоина, вот тогда её и латай мемоизацией. Всё остальное — от лукавого и ведёт к сложности, которую потом сам же и будешь ебашить.