Svelte

`$state`: реактивное состояние

Разработчик пишет let count равно 0, меняет count в обработчике клика и удивляется: число на экране не двигается. В Svelte 5 обычная переменная статична - компилятор не следит за ней. Чтобы значение стало живым и обновляло разметку при изменении, его объявляют через руну `$state`. С ней count меняется как самая обычная переменная (count++ работает), но за каждым изменением Svelte перерисует ровно то, что от count зависит. А для объектов и массивов `$state` идёт дальше: он делает их глубоко реактивными.

  • Счётчики, переключатели, поля ввода - любое локальное состояние компонента объявляется через `$state`
  • Корзина интернет-магазина: массив товаров в `$state`, добавление через push сразу обновляет интерфейс
  • Формы: объект с полями в `$state`, изменение вложенного поля реактивно отражается в превью
  • Общее состояние выносят в файл .svelte.js с `$state` и импортируют в разные компоненты
  • Состояние UI вроде открытой модалки или активной вкладки - типичный кандидат на `$state`

Предварительные знания

  • Общее понятие рун из вводного урока
  • JavaScript: объекты, массивы и их мутирующие методы (push, splice)
  • Знание разницы между присваиванием значения и мутацией объекта

Объявление и изменение состояния

Руна `$state` принимает начальное значение и возвращает реактивное состояние. После этого переменная ведёт себя как обычная: её читают по имени и меняют присваиванием. Разница в том, что Svelte отслеживает каждое изменение и обновляет ту разметку, где это значение используется. Никаких сеттеров, как в других фреймворках, не нужно.

Все привычные операции работают: count++ увеличивает, count-- уменьшает, count равно 0 сбрасывает. Директива bind:checked связывает чекбокс с состоянием agreed в обе стороны: клик по чекбоксу меняет переменную, а изменение переменной отражается на чекбоксе. Это и есть удобство `$state` - реактивность без церемоний.

В файлах .svelte.js и .svelte.ts руна `$state` тоже доступна, и так создают общее состояние вне компонента. Чтобы реактивность не терялась при импорте, такое состояние обычно оборачивают в объект с полем или экспортируют через функции-геттеры.

Что отличает переменную, объявленную через `$state`, от обычной let-переменной в Svelte 5?

Глубокая реактивность объектов и массивов

Когда в `$state` кладут объект или массив, Svelte оборачивает их в реактивный прокси. Реактивность глубокая: меняется не только сама ссылка, но и любое вложенное поле и любой элемент. Это значит, что мутирующие методы массива (push, splice, sort) вызывают обновление, и обновление поля во вложенном объекте тоже реактивно. Пересоздавать объект целиком не нужно.

Вызов cart.push добавляет элемент, и счётчик cart.length тут же обновляется - в большинстве других подходов пришлось бы присвоить новый массив. Изменение user.address.city во вложенном объекте тоже реактивно, потому что прокси охватывает всю структуру вглубь. Это снимает целый класс ошибок, когда забыли пересоздать объект и интерфейс не обновился.

  • Без глубокой реактивности (многие фреймворки) — Чтобы обновить интерфейс, нужно присвоить новую ссылку: создать новый массив или объект через spread. Мутация на месте часто игнорируется
  • С `$state` в Svelte 5 — Прокси отслеживает изменения вглубь. push, splice и присваивание вложенному полю работают и сразу обновляют разметку

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

Что произойдёт при вызове cart.push(item), если cart объявлен как `$state` пустого массива?

Когда `$state`, а когда обычная переменная

Не всё нужно делать реактивным. Руна `$state` нужна, когда изменение значения должно отразиться на интерфейсе или запустить производные значения и эффекты. Если значение вычисляется один раз и не влияет на отображение, обычной переменной достаточно. Лишний `$state` добавляет накладные расходы прокси и засоряет реактивный граф.

СлучайЧто выбрать
Значение меняется и видно в разметке`$state`
От значения зависят `$derived` или `$effect``$state`
Константа, заданная один разОбычная const-переменная
Промежуточный расчёт внутри функцииОбычная переменная
Значение из props без своей логики`$props`, не оборачивать в `$state`

Частая ошибка - оборачивать в `$state` значение, которое пришло из `$props` и не имеет собственной логики. Это создаёт копию, которая не синхронизируется с родителем. Если значение приходит снаружи и компонент его только показывает, оно читается прямо из `$props`.

В каком случае значение НЕ стоит оборачивать в `$state`?

Связь с другими темами

`$state` - источник реактивности, на котором стоят остальные руны модуля:

  • Руны: явная реактивность — `$state` - первая и базовая руна из общей карты
  • `$derived`: производные значения — Производные значения вычисляются из состояния `$state`
  • `$effect`: побочные эффекты — Эффекты запускаются в ответ на изменение `$state`

Итог

  • Руна `$state` превращает переменную в реактивное состояние: его изменение перерисовывает зависящую разметку
  • Менять состояние можно как обычную переменную: присваивание, count++, обновление поля объекта
  • Для объектов и массивов `$state` создаёт глубокий реактивный прокси: мутация вложенного поля или элемента тоже реактивна
  • Мутирующие методы массива (push, splice) работают и вызывают обновление, отдельного присваивания не нужно
  • Обычная переменная без `$state` подходит для значений, которые не должны перерисовывать интерфейс при изменении

Связанные уроки

  • sv-05-runes-intro — `$state` - первая из пяти рун, поэтому нужно общее понимание того, что такое руна
  • sv-07-derived — `$derived` вычисляет значения именно из реактивного состояния `$state`
  • sv-08-effect — `$effect` реагирует на изменения состояния, объявленного через `$state`
`$state`: реактивное состояние

0

1

Войти