Общее состояние между компонентами

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


Роли общего состояния

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

  1. Синхронизация данных — изменения в одном компоненте автоматически отражаются в других.
  2. Разделение ответственности — компоненты становятся «тонкими», концентрируясь на отображении данных, а не на их управлении.
  3. Упрощение масштабирования приложения — добавление новых компонентов, использующих те же данные, не требует изменений в уже существующих компонентах.

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

В Slim.js общий стейт обычно реализуется через внешний объект состояния или синглтон. Простейший пример:

export const store = {
    state: {
        user: null,
        notifications: []
    },
    subscribers: [],
    subscribe(callback) {
        this.subscribers.push(callback);
    },
    setState(newState) {
        this.state = { ...this.state, ...newState };
        this.subscribers.forEach(cb => cb(this.state));
    }
};
  • state — объект, содержащий актуальные данные.
  • subscribers — массив функций, которые вызываются при изменении состояния.
  • subscribe(callback) — метод для регистрации подписчиков.
  • setState(newState) — метод для обновления состояния и уведомления всех подписанных компонентов.

Подключение компонентов к общему состоянию

Компоненты Slim.js могут подписываться на изменения состояния через subscribe. Пример:

import { Slim } from 'slim-js';
import { store } from './store.js';

class UserProfile extends Slim {
    constructor() {
        super();
        this.user = null;
    }

    onBeforeCreated() {
        store.subscribe(state => {
            this.user = state.user;
            this.update();
        });
    }

    get template() {
        return `
            

User Profile

${this.user ? this.user.name : 'Гость'}

`; } } Slim.tag('user-profile', UserProfile);

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

  • Подписка происходит в onBeforeCreated, что гарантирует доступность данных до рендеринга.
  • Метод update() перерисовывает компонент при изменении данных.

Модификация состояния из компонентов

Компоненты могут не только читать, но и изменять общее состояние:

class LoginForm extends Slim {
    constructor() {
        super();
        this.username = '';
    }

    onLogin() {
        store.setState({ user: { name: this.username } });
    }

    get template() {
        return `
            
            
        `;
    }
}

Slim.tag('login-form', LoginForm);
  • Изменения состояния вызывают автоматическое обновление всех подписанных компонентов.
  • Компоненты не взаимодействуют напрямую друг с другом, связь происходит через общий стейт.

Реактивность и производительность

Slim.js использует легковесную реактивную систему, поэтому важно учитывать следующие моменты:

  • Обновления состояния должны быть минимальными и точечными. Изменение всего объекта state без нужды может вызвать лишние перерисовки.
  • Для больших приложений рекомендуется разбивать глобальное состояние на модули:
export const userStore = {
    state: { user: null },
    subscribers: [],
    setUser(user) {
        this.state.user = user;
        this.subscribers.forEach(cb => cb(this.state));
    },
    subscribe(cb) {
        this.subscribers.push(cb);
    }
};

export const notificationStore = {
    state: { notifications: [] },
    subscribers: [],
    addNotification(msg) {
        this.state.notifications.push(msg);
        this.subscribers.forEach(cb => cb(this.state));
    },
    subscribe(cb) {
        this.subscribers.push(cb);
    }
};

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


Двусторонняя привязка данных

Slim.js поддерживает двустороннюю привязку с помощью реактивных свойств. В связке с общим состоянием это выглядит так:


  • this.userName — локальное свойство компонента.
  • При вводе данных значение обновляется локально, а затем синхронизируется с глобальным состоянием через setState.

Организация больших приложений

Для больших приложений рекомендуется:

  1. Создавать отдельные файлы для состояния каждого модуля.
  2. Использовать селекторы для выборки нужной части состояния, чтобы компоненты подписывались только на актуальные данные.
  3. Минимизировать перерисовку компонентов через оптимизацию обновлений и проверку изменений данных перед вызовом update().

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

  • Полная реактивность без использования сторонних библиотек вроде Redux.
  • Прозрачное управление состоянием через подписки и обновления.
  • Упрощение тестирования компонентов, так как они становятся «чистыми», не зависящими от других частей приложения напрямую.