useMemo для мемоизации

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


Синтаксис и базовое использование

import { useMemo, html, component } from "atomico";

function ExpensiveComponent({ value }) {
    const computed = useMemo(() => {
        console.log("Вычисление...");
        return value * 2; // пример ресурсоёмкой операции
    }, [value]);

    return html`<div>Результат: ${computed}</div>`;
}

export default component(ExpensiveComponent);

Пояснения:

  • Первый аргумент useMemo — функция, которая возвращает вычисленное значение.
  • Второй аргумент — массив зависимостей. useMemo будет повторно вычислять значение только если изменится хотя бы одна зависимость.
  • Если массив зависимостей пустой, вычисление произойдёт один раз при первом рендере и никогда больше.

Когда применять useMemo

Основные сценарии:

  1. Тяжёлые вычисления внутри компонента Например, сортировка больших массивов, фильтрация или генерация сложных структур данных.

  2. Создание объектов или массивов для дочерних компонентов Если передавать каждый раз новый объект как пропс, дочерние компоненты будут перерендериваться, даже если данные не изменились. useMemo позволяет сохранять ссылку на объект, предотвращая лишние рендеры.

const list = useMemo(() => {
    return items.filter(item => item.active);
}, [items]);
  1. Оптимизация рендеринга больших списков В сочетании с виртуализацией или другими методами рендеринга, мемоизация данных значительно снижает нагрузку на DOM.

Отличие useMemo от useCallback

  • useMemo возвращает значение.
  • useCallback возвращает функцию, мемоизированную по зависимостям.

Пример использования вместе:

const handleClick = useCallback(() => {
    console.log("Клик", computedValue);
}, [computedValue]);

const computedValue = useMemo(() => expensiveCalculation(data), [data]);

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


Важные нюансы

  1. Не использовать для каждого выражения Излишняя мемоизация может ухудшить производительность из-за накладных расходов на хранение и сравнение зависимостей.

  2. Сравнение зависимостей Atomico использует строгую проверку Object.is для определения изменений зависимостей. Если зависимость — объект или массив, важно обновлять ссылку при изменении данных.

  3. Не использовать для побочных эффектов useMemo только мемоизирует значение. Любые сайд-эффекты должны выполняться в useEffect.

const memoizedData = useMemo(() => {
    return fetchData(); // не рекомендуется
}, [query]); // лучше использовать useEffect для запросов

Примеры продвинутого использования

Мемоизация сложного объекта для дочернего компонента:

const settings = useMemo(() => ({
    theme: selectedTheme,
    layout: layoutConfig,
}), [selectedTheme, layoutConfig]);

return html`<child-component .settings=${settings}></child-component>`;

Мемоизация вычислений с несколькими зависимостями:

const total = useMemo(() => {
    return products.reduce((sum, product) => sum + product.price * product.quantity, 0);
}, [products]);

Такое использование гарантирует, что сумма пересчитается только при изменении списка товаров.


Рекомендации по эффективному использованию

  • Мемоизировать только ресурсоёмкие вычисления.
  • Держать зависимостями только необходимые данные.
  • Сохранять ссылки на объекты и функции, передаваемые дочерним компонентам, для предотвращения лишних рендеров.
  • Следить за тем, чтобы мемоизация не усложняла код без необходимости.

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