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

В Svelte stores представляют собой реактивные контейнеры для состояния, которые позволяют компонентам подписываться на изменения и автоматически обновляться при изменении данных. Carbon Components Svelte активно использует эту концепцию для управления состоянием компонентов интерфейса, особенно в интерактивных элементах, таких как модальные окна, выпадающие списки, переключатели и формы.


Типы stores

В Svelte существуют три основных типа stores:

  1. Writable — полностью изменяемый store, поддерживает методы set и update.
  2. Readable — read-only store, подписчики могут только получать значение.
  3. Derived — производный store, вычисляется на основе одного или нескольких других stores.

Пример создания writable store для управления состоянием модального окна:

import { writable } from 'svelte/store';

export const modalOpen = writable(false);

Изменение состояния осуществляется через методы:

modalOpen.set(true);      // открывает модальное окно
modalOpen.update(value => !value);  // переключает состояние

Подписка на store

Чтобы компонент реагировал на изменение состояния, необходимо подписаться на store. В Svelte это делается через $-синтаксис:

<script>
  import { modalOpen } from './stores.js';
</script>

{#if $modalOpen}
  <div class="modal">Содержимое модального окна</div>
{/if}

Использование $modalOpen автоматически подписывает компонент на изменения store и пересчитывает разметку при каждом изменении значения.


Интеграция с компонентами Carbon

Большинство компонентов Carbon Svelte используют внутренние stores для управления состоянием. Примеры:

  • Checkbox: управляет состоянием выбора через store.
  • Dropdown: управляет открытием/закрытием и выбранным элементом.
  • Modal: управляет видимостью через булев store.

Пример управления состоянием выпадающего списка:

<script>
  import { Dropdown } from 'carbon-components-svelte';
  import { writable } from 'svelte/store';

  const selectedItem = writable('option1');
</script>

<Dropdown
  bind:value={$selectedItem}
  items={['option1', 'option2', 'option3']}
  label="Выберите опцию"
/>

Здесь bind:value={$selectedItem} связывает store с выбранным элементом dropdown. Любое изменение выбора автоматически обновляет store, а подписанные компоненты получают актуальное значение.


Производные store для сложного состояния

Иногда необходимо вычислять состояние на основе нескольких store. Для этого используются derived stores:

import { derived } from 'svelte/store';
import { modalOpen, selectedItem } from './stores.js';

export const modalInfo = derived(
  [modalOpen, selectedItem],
  ([$modalOpen, $selectedItem]) => ({
    visible: $modalOpen,
    option: $selectedItem
  })
);

В компоненте можно использовать:

{#if $modalInfo.visible}
  <div class="modal">
    Выбранная опция: {$modalInfo.option}
  </div>
{/if}

Best practices в Carbon Components Svelte

  • Локальные и глобальные store: Для маленьких компонентов удобно использовать локальные writable store внутри компонента. Для приложения с множеством взаимосвязанных компонентов лучше выделять глобальные store.
  • Unsubscribe: При использовании store.subscribe вручную всегда важно отписываться, чтобы избежать утечек памяти.
  • Bind и реактивность: Использование bind:value в компонентах Carbon обеспечивает двустороннюю привязку store и состояния компонента, упрощая синхронизацию.
  • Derived для чистоты кода: Для сложных вычислений лучше использовать derived store, чтобы отделять логику состояния от представления.

Пример комплексного управления состоянием

Создадим форму с несколькими компонентами Carbon и управлением через store:

<script>
  import { TextInput, Checkbox, Dropdown } from 'carbon-components-svelte';
  import { writable, derived } from 'svelte/store';

  const name = writable('');
  const agreeTerms = writable(false);
  const selectedRole = writable('user');

  const canSubmit = derived(
    [name, agreeTerms],
    ([$name, $agreeTerms]) => $name.trim().length > 0 && $agreeTerms
  );
</script>

<TextInput bind:value={$name} label="Имя" />
<Checkbox bind:checked={$agreeTerms} label="Согласен с условиями" />
<Dropdown bind:value={$selectedRole} items={['user','admin']} label="Роль" />
<button disabled={!$canSubmit}>Отправить</button>
  • canSubmit автоматически вычисляет возможность отправки формы.
  • Компоненты Carbon синхронизированы с store через bind.
  • Любое изменение состояния немедленно отражается в интерфейсе.

Заключение по Stores в Carbon Components Svelte

Использование store позволяет:

  • Централизовать управление состоянием.
  • Легко синхронизировать несколько компонентов.
  • Поддерживать чистый и реактивный код без лишних методов обновления DOM.

Stores в Carbon Svelte интегрированы с компонентами через bind и подписки, что делает управление состоянием простым и мощным инструментом для создания сложных интерфейсов.