Singleton компоненты

Singleton компонент в Atomico — это компонент, который существует в приложении в единственном экземпляре и управляется централизованно. Такой подход позволяет создавать глобальные состояния и сервисы, доступные из любых частей интерфейса, без необходимости передавать их через пропсы или контекст. В Atomico singleton-компоненты строятся на основе обычных функциональных компонентов с использованием специальных хуков и глобального реестра.


Создание singleton-компонента

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

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

function GlobalStore() {
    const [state, setState] = useState({ user: null, theme: "light" });

    const login = (user) => setState({ ...state, user });
    const logout = () => setState({ ...state, user: null });
    const toggleTheme = () =>
        setState({ ...state, theme: state.theme === "light" ? "dark" : "light" });

    return {
        state,
        login,
        logout,
        toggleTheme,
    };
}

// Регистрация singleton
export const globalStore = useSingleton(GlobalStore);

export const globalStoreElement = c(GlobalStore);

Ключевые моменты:

  • useSingleton гарантирует создание только одного экземпляра компонента.
  • Возвращаемое значение — объект с методами и состоянием, доступный глобально.
  • Такой компонент можно подключать в любом месте приложения без повторного создания.

Подключение singleton в других компонентах

Для использования singleton-компонента в других местах приложения применяют хук useSingleton или импорт напрямую из реестра:

import { c, useEffect } from "atomico";
import { globalStore } from "./GlobalStore";

function UserProfile() {
    const { state, logout } = globalStore();

    useEffect(() => {
        console.log("Текущий пользователь:", state.user);
    }, [state.user]);

    return (
        <host>
            {state.user ? (
                <div>
                    <p>Пользователь: {state.user.name}</p>
                    <button onCl ick={logout}>Выйти</button>
                </div>
            ) : (
                <p>Пользователь не авторизован</p>
            )}
        </host>
    );
}

export const userProfile = c(UserProfile);

Особенности использования:

  • Любые изменения состояния singleton автоматически отражаются во всех компонентах, использующих его.
  • Singleton-компоненты могут хранить методы для управления глобальным поведением приложения.
  • Использование глобального состояния через singleton упрощает архитектуру и уменьшает вложенность пропсов.

Реактивность singleton-компонентов

Atomico позволяет создавать реактивные состояния внутри singleton-компонентов с помощью useState и useReducer. Любые изменения состояния автоматически вызывают перерисовку всех подключённых компонентов:

function NotificationStore() {
    const [notifications, setNotifications] = useState([]);

    const addNotification = (message) =>
        setNotifications([...notifications, { id: Date.now(), message }]);

    const removeNotification = (id) =>
        setNotifications(notifications.filter(n => n.id !== id));

    return { notifications, addNotification, removeNotification };
}

export const notificationStore = useSingleton(NotificationStore);

Особенности реактивности:

  • Любой компонент, подписанный на singleton, реагирует на изменения без дополнительных усилий.
  • Можно комбинировать несколько singleton-компонентов для построения комплексных глобальных сервисов.

Ленивая инициализация singleton

Singleton-компоненты можно создавать лениво, чтобы их состояние и методы не инициализировались до первого использования. Это полезно для оптимизации загрузки приложения.

import { useSingletonLazy } from "atomico";

export const lazyStore = useSingletonLazy(() => {
    const [count, setCount] = useState(0);
    return {
        count,
        increment: () => setCount(count + 1),
    };
});

Преимущества ленивой инициализации:

  • Singleton создаётся только при первом обращении.
  • Снижается нагрузка на память и время инициализации.
  • Удобно для редко используемых сервисов.

Singleton и Shadow DOM

Atomico компоненты используют Shadow DOM, что позволяет singleton-компонентам безопасно хранить свои стили и состояния, не влияя на остальную часть приложения. Несмотря на изоляцию стилей, состояние singleton остаётся глобально доступным через реестр:

import { c } from "atomico";
import { globalStore } from "./GlobalStore";

function ThemeSwitcher() {
    const { state, toggleTheme } = globalStore();

    return (
        <host shadowDom>
            <button onCl ick={toggleTheme}>
                Тема: {state.theme === "light" ? "Светлая" : "Тёмная"}
            </button>
        </host>
    );
}

export const themeSwitcher = c(ThemeSwitcher);

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

  • Singleton-компоненты сохраняют независимость от Shadow DOM других компонентов.
  • Глобальное состояние доступно в любом Shadow DOM без конфликтов.

Рекомендации по структуре singleton

  1. Разделение ответственности: Каждый singleton должен решать одну задачу (например, хранение пользователя, уведомлений или темы).
  2. Чистота интерфейса: Возвращать только необходимые методы и состояние.
  3. Поддержка реактивности: Использовать useState или useReducer для динамических изменений.
  4. Централизация доступа: Импортировать singleton из одного файла для предотвращения дублирования.

Singleton-компоненты в Atomico создают мощный инструмент для организации глобальных состояний и сервисов, сохраняя при этом реактивность и модульность приложения.