Atomico — это библиотека для создания веб-компонентов с реактивным поведением. Ключевой элемент её архитектуры — механизм отслеживания изменений состояния, который позволяет компонентам автоматически обновлять представление при изменении данных. В этой статье рассматриваются основные принципы работы реактивности в Atomico, способы её настройки и оптимизации.
В основе реактивной системы лежат реактивные
объекты. Любое состояние компонента, которое должно быть
отслеживаемым, создаётся через useState или
useRef:
import { useState, html, component } from "atomico";
function Counter() {
const [count, setCount] = useState(0);
return html`
<div>
<p>Счёт: ${count}</p>
<button oncl ick=${() => setCount(count + 1)}>Увеличить</button>
</div>
`;
}
export default component(Counter);
Ключевые моменты:
useState возвращает массив
[значение, функция изменения].setCount автоматически
инициирует перерендер компонента.Для сложных структур данных (объектов и массивов) реактивность требует особого подхода. Atomico не отслеживает вложенные свойства по умолчанию, поэтому изменения должны быть явными:
const [state, setState] = useState({ items: [] });
// Добавление элемента
setState({
...state,
items: [...state.items, "новый элемент"]
});
Важно:
spread,
slice) гарантирует корректное срабатывание
перерендеринга.state.items.push(...)) не инициирует обновление.Для отслеживания побочных эффектов применяются хуки
useEffect и useEvent:
useEffect(() => {
console.log("Состояние изменилось:", state.items);
}, [state.items]);
useEffect вызывается после каждого перерендеринга, если
изменились указанные зависимости.useEvent для регистрации событий,
реагирующих на конкретные изменения состояния.useRefuseRef позволяет хранить данные, которые не должны
автоматически инициировать ререндер, но могут быть реактивными при
необходимости:
const countRef = useRef(0);
function increment() {
countRef.current++;
// Для триггера рендера нужно вызвать setState или useUpdate
}
Ключевые отличия useRef от
useState:
useRef хранит мутируемое значение,
которое не вызывает автоматический ререндер.Atomico применяет эффективный алгоритм сравнения виртуального DOM, поэтому перерендер происходит только при реальных изменениях состояния. Для оптимизации рекомендуется:
Минимизировать вложенные объекты. Чем меньше глубина структуры, тем проще библиотеке определить изменения.
Использовать иммутабельные операции. Любое изменение объекта должно создавать новый объект.
Разделять состояние на независимые хуки. Каждое
отдельное состояние через useState отслеживается отдельно,
что снижает нагрузку на рендеринг.
Atomico интегрирует реактивные значения напрямую в шаблоны через
html:
html`
<ul>
${state.items.map(item => html`<li>${item}</li>`)}
</ul>
`;
state.items автоматически пересоздаёт
список <li>.Для комплексных компонентов с множеством взаимозависимых состояний
используется комбинация useState, useRef и
useEffect. Пример:
function TodoList() {
const [todos, setTodos] = useState([]);
const lastAdded = useRef(null);
useEffect(() => {
if (lastAdded.current) {
console.log("Добавлена новая задача:", lastAdded.current);
}
}, [todos]);
function addTodo(text) {
const newTodo = { text, done: false };
lastAdded.current = newTodo;
setTodos([...todos, newTodo]);
}
return html`
<div>
<button oncl ick=${() => addTodo("Новая задача")}>Добавить</button>
<ul>
${todos.map(todo => html`<li>${todo.text}</li>`)}
</ul>
</div>
`;
}
useRef хранит последний добавленный объект без лишнего
ререндеринга.useEffect реагирует на изменение todos,
фиксируя точный момент добавления нового элемента.Механизм отслеживания изменений в Atomico обеспечивает гибкую и предсказуемую реактивность. Он опирается на реактивные хуки, иммутабельные структуры и эффективный алгоритм сравнения виртуального DOM, что позволяет создавать компоненты с минимальной нагрузкой и предсказуемым поведением при любых изменениях состояния.