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

Bliss.js предоставляет лёгкий и эффективный механизм работы с состоянием приложения, позволяя управлять данными, их изменениями и реакциями на эти изменения без громоздких паттернов. Центральным элементом управления состоянием является объект Store, который служит контейнером для данных и обеспечивает подписку на их изменения.

Создание и инициализация состояния

Состояние создаётся через конструктор Bliss.Store:

const store = new Bliss.Store({
    user: {
        name: 'Алексей',
        loggedIn: false
    },
    cart: []
});

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

  • Store может содержать вложенные объекты и массивы.
  • Любое свойство состояния становится реактивным автоматически.
  • Инициализация с дефолтными значениями позволяет сразу задать начальное состояние приложения.

Чтение состояния

Доступ к данным осуществляется через методы .get() или прямое обращение к свойствам объекта состояния:

const username = store.get('user.name'); // 'Алексей'
const cartItems = store.get('cart');    // []
  • Метод .get() поддерживает dot-notation, что упрощает работу с вложенными объектами.
  • Прямое обращение к свойствам также возможно: store.state.user.name, но использование .get() обеспечивает защиту от ошибок при доступе к несуществующим ключам.

Изменение состояния

Для изменения состояния применяется метод .set():

store.set('user.loggedIn', true);
store.set('cart', [...store.get('cart'), { id: 1, name: 'Товар' }]);

Особенности работы с .set():

  • Поддерживается immutable-подход при работе с массивами и объектами.
  • При изменении состояния автоматически уведомляются все подписчики, привязанные к соответствующим ключам.
  • Можно обновлять несколько ключей одновременно:
store.set({
    'user.name': 'Ирина',
    'user.loggedIn': false
});

Подписка на изменения

Bliss.js позволяет реагировать на изменение состояния через метод .subscribe():

store.subscribe('user.loggedIn', (newValue, oldValue) => {
    console.log(`Статус входа изменён: ${oldValue} → ${newValue}`);
});

Особенности подписок:

  • Можно подписываться на конкретные ключи или на всё состояние сразу.
  • Подписчики вызываются только при действительном изменении значения.
  • Подписка возвращает функцию для отписки:
const unsubscribe = store.subscribe('cart', items => console.log(items));
unsubscribe(); // удаляет подписку

Реактивные вычисления

Bliss.js поддерживает вычисляемые свойства через метод .computed():

store.computed('cartTotal', state => {
    return state.cart.reduce((sum, item) => sum + item.price, 0);
});

console.log(store.get('cartTotal')); // вычисляемая сумма товаров

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

  • Вычисляемое свойство автоматически пересчитывается при изменении зависимых данных.
  • Можно использовать вложенные зависимости, что позволяет строить сложные динамические значения.

Работа с массивами

Для массивов доступны методы с автоматической реактивностью:

store.push('cart', { id: 2, name: 'Ещё товар', price: 500 });
store.splice('cart', 0, 1); // удаляет первый элемент
store.update('cart', item => item.id === 2 ? { ...item, price: 450 } : item);
  • Методы push, splice, update обеспечивают уведомление подписчиков о изменениях.
  • Применяется подход immutability, где исходный массив не изменяется напрямую, а создаётся новый.

Глубокое наблюдение

Bliss.js позволяет отслеживать изменения не только верхнего уровня, но и вложенных объектов:

store.subscribe('user', user => {
    console.log('Пользователь обновлён', user);
});
  • Подписка на объект отслеживает любые изменения его свойств.
  • Можно комбинировать с computed-свойствами для реактивного интерфейса.

Интеграция с DOM

Bliss.js легко интегрируется с HTML через директивы или ручное связывание:

const nameInput = document.querySelector('#username');
store.subscribe('user.name', value => nameInput.value = value);

nameInput.addEventListener('input', e => {
    store.set('user.name', e.target.value);
});
  • Автоматическая реактивность позволяет минимизировать ручные обновления DOM.
  • Поддерживаются двусторонние связи, что особенно удобно при работе с формами и списками.

Асинхронные обновления

Для асинхронных операций Bliss.js использует промисы или async/await:

async function fetchUserData() {
    const response = await fetch('/api/user');
    const data = await response.json();
    store.set('user', data);
}
  • Подписки на состояние гарантируют обновление интерфейса после завершения асинхронной операции.
  • Можно создавать цепочки вычислений, зависящие от асинхронных данных.

Практика структурирования состояния

Рекомендуется структурировать состояние по логическим модулям, что упрощает управление:

const store = new Bliss.Store({
    user: { name: '', loggedIn: false },
    cart: [],
    products: [],
    notifications: []
});
  • Каждый модуль можно подписывать отдельно.
  • Упрощает тестирование и поддержку больших приложений.

Bliss.js сочетает простоту и гибкость в управлении состоянием, позволяя строить как небольшие динамичные виджеты, так и масштабные интерфейсы с глубокой реактивностью и строгим контролем над данными. Взаимодействие с объектами состояния, массивами и вычисляемыми свойствами создаёт единый реактивный поток, минимизируя необходимость ручной синхронизации с DOM.