Разделение состояния

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

Основы состояния в Atomico

Состояние в Atomico представлено через реактивные объекты, создаваемые с помощью функции useState. Эти объекты автоматически отслеживают изменения и инициируют обновление соответствующего компонента.

Пример базового состояния:

import { c, useState } from "atomico";

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

    return (
        <host>
            <button oncl ick={() => setCount(count + 1)}>Увеличить</button>
            <p>{count}</p>
        </host>
    );
}

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

Каждый вызов useState возвращает текущее значение состояния и функцию для его обновления. Важно, что состояние локально для компонента, поэтому изменение count внутри одного Counter не затронет другие экземпляры.

Создание общего состояния

Чтобы разделить состояние между компонентами, используется контекст или глобальные реактивные объекты. Atomico предоставляет возможность создавать реактивные объекты вне компонентов, что позволяет использовать их как общий источник данных.

Пример глобального состояния:

import { reactive, c, useReactive } from "atomico";

const store = reactive({ count: 0 });

function Counter() {
    const state = useReactive(store);

    return (
        <host>
            <button oncl ick={() => state.count++}>Увеличить</button>
            <p>{state.count}</p>
        </host>
    );
}

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

В этом примере любое изменение store.count автоматически отражается во всех компонентах, которые используют useReactive(store).

Преимущества такого подхода:

  • Единая точка правды для данных.
  • Автоматическая синхронизация между компонентами.
  • Упрощение логики компонентов, поскольку нет необходимости передавать состояние через свойства (props).

Контексты для передачи состояния

Для более гибкого управления состоянием можно использовать контексты, аналогичные React Context, которые позволяют компоненту объявить состояние и предоставить его дочерним компонентам.

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

const CounterContext = createContext();

function CounterProvider({ children }) {
    const [count, setCount] = useState(0);
    return (
        <host>
            <CounterContext.Provider value={{ count, setCount }}>
                {children}
            </CounterContext.Provider>
        </host>
    );
}

function CounterDisplay() {
    const { count, setCount } = useContext(CounterContext);

    return (
        <host>
            <button oncl ick={() => setCount(count + 1)}>Увеличить</button>
            <p>{count}</p>
        </host>
    );
}

customElements.define("x-counter-display", c(CounterDisplay));
customElements.define("x-counter-provider", c(CounterProvider));

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

Разделение и модульность состояния

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

// store/counter.js
import { reactive } from "atomico";

export const counterStore = reactive({ count: 0 });

// components/Counter.js
import { c, useReactive } from "atomico";
import { counterStore } from "../store/counter";

function Counter() {
    const state = useReactive(counterStore);

    return (
        <host>
            <button oncl ick={() => state.count++}>Увеличить</button>
            <p>{state.count}</p>
        </host>
    );
}

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

Модульное разделение состояния повышает масштабируемость, упрощает тестирование и снижает связанность компонентов.

Влияние на производительность

Atomico автоматически оптимизирует обновления компонентов. Использование разделяемого состояния уменьшает количество повторных рендеров, если компоненты используют только необходимые части состояния.

Советы по оптимизации:

  • Разделять состояния на логические единицы, чтобы изменения одного поля не перерендеривали все компоненты.
  • Использовать useReactive вместо передачи всего объекта через props для предотвращения лишних обновлений.
  • Для сложных вычисляемых данных применять computed свойства, которые пересчитываются только при изменении зависимостей.

Выводы по организации разделенного состояния

  • Локальное состояние (useState) подходит для компонентов с изолированными данными.
  • Глобальное реактивное состояние (reactive) обеспечивает синхронизацию между компонентами.
  • Контексты позволяют гибко делиться состоянием внутри иерархии компонентов.
  • Модульное разделение состояния повышает читаемость и масштабируемость приложения.
  • Продуманное управление состоянием улучшает производительность и снижает количество лишних перерисовок.

Разделение состояния является фундаментом архитектуры Atomico и позволяет создавать приложения, где данные управляются централизованно, а компоненты остаются максимально независимыми и реактивными.