Mutation Observer — это механизм отслеживания
изменений в DOM, предоставляющий высокую производительность по сравнению
с устаревшими событиями типа DOMSubtreeModified. В
библиотеке Atomico он используется для реактивного реагирования на
изменения элементов и их атрибутов, что особенно важно при построении
веб-компонентов с динамическим поведением.
В Atomico useMutationObserver является хуком, который
позволяет подписываться на изменения DOM-узлов внутри компонента.
Сигнатура функции выглядит следующим образом:
import { useMutationObserver } from "atomico";
function MyComponent() {
const ref = useRef();
useMutationObserver(ref, (mutations) => {
for (const mutation of mutations) {
console.log(mutation.type, mutation.target);
}
}, { attributes: true, childList: true, subtree: true });
return <div ref={ref}>Контент</div>;
}
Ключевые моменты:
ref — ссылка на DOM-элемент, за изменениями которого
необходимо наблюдать.
Колбек вызывается при любом изменении, указанном в конфигурации.
Третий аргумент — объект MutationObserverInit, где
можно включить наблюдение за:
attributes — изменения атрибутов.childList — добавление или удаление дочерних
элементов.subtree — наблюдение за всеми вложенными
элементами.characterData — изменения текстового содержимого.Объект конфигурации позволяет точно указать, какие изменения отслеживать:
{
attributes: true, // Отслеживание атрибутов
attributeFilter: ["class", "style"], // Только указанные атрибуты
childList: true, // Добавление или удаление дочерних элементов
subtree: false, // Вложенные элементы не отслеживаются
characterData: true // Изменение текста внутри элементов
}
Использование attributeFilter помогает снизить нагрузку,
отслеживая только необходимые атрибуты.
В Atomico наблюдатели часто используются совместно с реактивными свойствами и состояниями. Например, можно обновлять состояние компонента при добавлении новых элементов:
import { c, useState, useMutationObserver } from "atomico";
function TodoList() {
const [count, setCount] = useState(0);
const ref = useRef();
useMutationObserver(ref, (mutations) => {
const addedNodes = mutations.flatMap(m => Array.from(m.addedNodes));
if (addedNodes.length) setCount(count + addedNodes.length);
}, { childList: true, subtree: true });
return (
<host>
<div ref={ref}>
<slot></slot>
</div>
<p>Количество элементов: {count}</p>
</host>
);
}
customElements.define("todo-list", c(TodoList));
Особенности подхода:
MutationObserver позволяет компоненту реагировать на
изменения слота, даже если добавление происходит извне.count автоматически синхронизируется с
количеством дочерних элементов.Atomico интегрирует наблюдателей с жизненным циклом компонента.
Наблюдатель автоматически отключается при размонтировании, если
используется хук useMutationObserver, что предотвращает
утечки памяти.
При ручном создании наблюдателя можно использовать стандартный API:
const observer = new MutationObserver(callback);
observer.observe(element, { childList: true });
// В момент размонтирования
observer.disconnect();
subtree: true, чтобы отслеживать внешние вставки.useState или useReducer для автоматического
обновления интерфейса.useMutationObserver(ref, (mutations) => {
mutations.forEach(mutation => {
if (mutation.type === "attributes") {
console.log("Атрибут изменен:", mutation.attributeName);
}
if (mutation.type === "characterData") {
console.log("Текст изменен:", mutation.target.data);
}
});
}, { attributes: true, characterData: true, subtree: true });
useMutationObserver(ref, (mutations) => {
const newItems = mutations
.flatMap(m => Array.from(m.addedNodes))
.filter(node => node.tagName === "LI");
if (newItems.length) console.log("Добавлены новые элементы списка:", newItems);
}, { childList: true, subtree: true });
Такой подход позволяет точно контролировать динамическое содержимое, не перегружая колбек лишними событиями.
MutationObserver в Atomico является мощным инструментом
для реактивной работы с DOM. Он позволяет отслеживать изменения в
атрибутах, тексте и структуре элементов, интегрируется с хуками и
состояниями компонентов, обеспечивает высокую производительность и
предотвращает утечки памяти при правильном использовании. В сочетании с
реактивными механизмами Atomico он становится фундаментом для построения
сложных и динамических веб-компонентов.