Мемоизация является ключевым механизмом для оптимизации производительности компонентов в библиотеке Haunted. Она позволяет кэшировать вычисленные значения и предотвращать повторные, дорогостоящие вычисления при рендеринге компонентов, особенно если входные данные не изменились. В Haunted мемоизация тесно связана с реактивностью и хуками.
useMemoВ Haunted используется хук useMemo, который служит
аналогом React useMemo. Он принимает два аргумента:
import { html, component, useMemo } from 'haunted';
function ExpensiveComponent({ num }) {
const factorial = useMemo(() => {
console.log('Вычисление факториала');
const calcFactorial = n => (n <= 1 ? 1 : n * calcFactorial(n - 1));
return calcFactorial(num);
}, [num]);
return html`<p>Факториал числа ${num} равен ${factorial}</p>`;
}
customElements.define('expensive-component', component(ExpensiveComponent));
В этом примере вычисление факториала выполняется только при
изменении num. Если значение num не
меняется между рендерами, хук возвращает сохранённый результат, экономя
ресурсы.
useMemoЗависимости определяют пересчёт: Если массив
зависимостей пустой ([]), вычисление произойдёт
только один раз при монтировании компонента.
Функция вычисления выполняется лениво:
useMemo не запускает функцию на каждом рендере, а только
когда изменяются зависимости.
Сравнение зависимостей по ссылке: Для объектов, массивов и функций пересчет будет происходить при каждой новой ссылке, даже если содержимое одинаково. Для сложных структур рекомендуется использовать мемоизированные объекты или функции.
Мемоизация полезна не только для числовых вычислений, но и для подготовки структур данных, фильтров, сортировок и трансформаций:
function FilteredList({ items, filter }) {
const filteredItems = useMemo(() => {
console.log('Фильтрация списка');
return items.filter(item => item.includes(filter));
}, [items, filter]);
return html`
<ul>
${filteredItems.map(item => html`<li>${item}</li>`)}
</ul>
`;
}
При изменении только filter пересчитывается
фильтрованный список, но если список items остаётся
неизменным, вычисления не повторяются.
useCallbackИногда требуется мемоизация функций, чтобы их ссылка
оставалась стабильной между рендерами. В Haunted для этого используется
хук useCallback:
import { useCallback } from 'haunted';
function Counter({ initial }) {
const [count, setCount] = useState(initial);
const increment = useCallback(() => setCount(c => c + 1), []);
return html`
<p>Счёт: ${count}</p>
<button @click=${increment}>Увеличить</button>
`;
}
increment сохраняет одну и ту же ссылку на функцию между
рендерами, что предотвращает лишние пересоздания при передаче в дочерние
компоненты.
Избегать ненужной мемоизации: мемоизация имеет небольшой накладной расход на хранение кэша и сравнение зависимостей. Для лёгких вычислений она не требуется.
Использовать мемоизацию для тяжёлых вычислений: фильтры больших массивов, сложные математические операции, трансформации данных.
Следить за зависимостями: всегда указывать все переменные, от которых зависит вычисляемое значение, иначе результат может устаревать.
Ленивые вычисления: useMemo
вычисляет значение только по необходимости, что уменьшает нагрузку при
частых рендерах.
Мемоизация нескольких вычислений одновременно:
function Dashboard({ data }) {
const totalUsers = useMemo(() => data.length, [data]);
const activeUsers = useMemo(() => data.filter(u => u.active).length, [data]);
return html`
<div>
<p>Всего пользователей: ${totalUsers}</p>
<p>Активные пользователи: ${activeUsers}</p>
</div>
`;
}
Сочетание с useCallback для оптимизации
событий:
function Search({ items }) {
const [query, setQuery] = useState('');
const handleInput = useCallback(e => setQuery(e.target.value), []);
const results = useMemo(() => items.filter(item => item.includes(query)), [items, query]);
return html`
<input type="text" @input=${handleInput} placeholder="Поиск..." />
<ul>
${results.map(item => html`<li>${item}</li>`)}
</ul>
`;
}
Мемоизация в Haunted обеспечивает эффективное управление
вычислениями, снижает нагрузку на DOM и CPU и позволяет
создавать компоненты с высоким уровнем производительности. Сочетание
useMemo и useCallback является стандартной
практикой при работе с динамическими данными и сложными рендерами.