Архитектурные паттерны

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

В основе Atomico лежит функциональный подход к компонентам, где каждый компонент является функцией, возвращающей описание DOM через JSX. Состояние управляется через встроенные хукоподобные механизмы, что обеспечивает реактивность и чистоту кода.


Компоненты и их структура

Компонент в Atomico определяется как функция с аргументом props:

import { c, useState } from "atomico";

function Counter(props) {
    const [count, setCount] = useState(0);

    return (
        <host shadowDom>
            <div>{count}</div>
            <button oncl ick={() => setCount(count + 1)}>Increment</button>
        </host>
    );
}

customElements.define("my-counter", c(Counter));

Ключевые моменты структуры:

  • <host> — специальный тег, который заменяет корневой DOM-узел компонента, управляет Shadow DOM, стилями и событиями.
  • c() — функция-обёртка для регистрации компонента как кастомного элемента.
  • useState() — реактивное состояние компонента. Изменение состояния автоматически вызывает повторный рендер.

Жизненный цикл компонентов

Atomico реализует понятие реактивного жизненного цикла через хуки:

  • useState — хранение локального состояния.
  • useEffect — выполнение побочных эффектов при изменении зависимостей.
  • useMemo и useCallback — оптимизация вычислений и функций, предотвращающая лишние рендеры.
  • useRef — сохранение ссылок на DOM-элементы или mutable-значения между рендерами.

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

import { c, useState, useEffect } from "atomico";

function Timer() {
    const [seconds, setSeconds] = useState(0);

    useEffect(() => {
        const id = setInterval(() => setSeconds(s => s + 1), 1000);
        return () => clearInterval(id); // очистка при размонтировании
    }, []);

    return <host>{seconds} секунд прошло</host>;
}

useEffect позволяет интегрировать асинхронные операции и управлять ресурсами, предотвращая утечки памяти.


Роутинг и композиция компонентов

Atomico поддерживает композицию компонентов на основе вложенных элементов. Компоненты могут быть переиспользуемыми и настраиваемыми через props:

function Card({ title, content }) {
    return (
        <host shadowDom>
            <h2>{title}</h2>
            <p>{content}</p>
        </host>
    );
}

function App() {
    return (
        <host>
            <Card title="Заголовок" content="Описание карточки" />
            <Card title="Ещё один заголовок" content="Другой контент" />
        </host>
    );
}

Такой подход формирует архитектурный паттерн “композиция поверх наследования”, который уменьшает связность и увеличивает модульность приложения.


Управление состоянием и реактивные потоки

Atomico предлагает реактивное состояние через Signals (useSignal) для более сложной логики:

import { c, useSignal } from "atomico";

function Slider() {
    const value = useSignal(50);

    return (
        <host>
            <input type="range" min="0" max="100" value={value.value} 
                   onin put={e => value.value = e.target.value} />
            <span>{value.value}</span>
        </host>
    );
}

Особенности Signals:

  • Автоматическая реактивность — при изменении value.value все связанные части интерфейса обновляются.
  • Поддержка нескольких подписчиков — несколько компонентов могут синхронно реагировать на одно состояние.
  • Оптимизация рендеринга — обновляются только затронутые DOM-узлы.

Архитектурные паттерны в Atomico

  1. Функциональные компоненты с хуками — основной паттерн для управления состоянием и жизненным циклом.
  2. Композиция компонентов — разделение интерфейса на мелкие независимые части, легко тестируемые и переиспользуемые.
  3. Реактивные сигналы и эффекты — построение реактивных потоков данных без сложных глобальных менеджеров состояния.
  4. Shadow DOM и изоляция стилей — создание модульных компонентов, которые не влияют на остальной документ.
  5. Хранение состояния вне DOM — минимизация мутаций напрямую в дереве DOM, что повышает производительность.

Интеграция с внешними библиотеками

Atomico легко интегрируется с другими инструментами:

  • Сторонние UI-библиотеки через обычный JSX.
  • Глобальные состояния через Signals или контекст (createContext).
  • Асинхронные данные через useEffect и fetch, обеспечивая реактивное обновление интерфейса.

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

import { c, createContext, useContext } from "atomico";

const ThemeContext = createContext("light");

function ThemedButton() {
    const theme = useContext(ThemeContext);
    return <host class={theme}>Нажми меня</host>;
}

Контекст позволяет передавать данные через дерево компонентов без необходимости пробрасывать props на каждом уровне.


Стратегии оптимизации

  • Разделение компонентов на чистые и эффектные.
  • Использование useMemo и useCallback для предотвращения лишних перерасчётов.
  • Минимизация обновлений Shadow DOM, обновляя только необходимые элементы.
  • Использование Signals для управления состоянием без лишних ререндеров.

Эти подходы формируют основу архитектурной дисциплины в проектах на Atomico, делая код масштабируемым и предсказуемым.