$bindable в Svelte: Упрощение работы с двухсторонними привязками
-
$bindable— это специальная директива в Svelte 5+, которая позволяет помечать переменные как двухсторонне связуемые (bindable) в рамках компонента. Это означает, что вы можете использовать bind: на кастомных компонентах так же, как вы используете его, например, на нативном элементе<input bind:value>Ранее для этого требовалось писать отдельный механизм обработки событий (dispatch) и передачи значений обратно, но теперь всё это можно сделать с минимальным кодом благодаря $bindable.
Как работает $bindable
Когда вы пишете:
let count = $bindable(0);Вы создаёте реактивное свойство, которое:
- Реактивно обновляется при изменении локально.
- Автоматически генерирует событие change при изменении значения.
- Позволяет использовать bind: в родительском компоненте без дополнительного кода.
Под капотом
$bindableоборачивает значение в реактивную ссылку и подписывается на изменения, чтобы оповещать внешний мир через dispatch(‘change’, …). Таким образом, вы получаете прозрачный механизм двусторонней связи между компонентами.Сравнение с другими фреймворками
В современных фреймворках для работы с состоянием между компонентами используются разные подходы. В Svelte 5+ появился инструмент
$bindable, который упрощает создание двусторонних привязок. В Vue для этого традиционно используютv-modelи события, а в React — пропсы и колбэк-функции. Рассмотрим, как эти механизмы работают, их сходства и различия.Двухсторонняя привязка: $bindable (Svelte), v-model (Vue), props + callbacks (React)
Svelte: $bindable
<!-- Counter.svelte --> <script> let count = $bindable(0); </script> <button on:click={() => count += 1}>Увеличить</button><!-- Родительский компонент --> <Counter bind:count={myCount} />$bindableавтоматически генерирует событие change при изменении значения.- Родитель может использовать bind:propName для синхронизации.
Vue: v-model и события
<!-- Counter.vue --> <template> <button @click="increment">Увеличить</button> </template> <script setup> import { ref } from 'vue'; const props = defineProps(['modelValue']); const emit = defineEmits(['update:modelValue']); function increment() { emit('update:modelValue', props.modelValue + 1); } </script><!-- Родительский компонент --> <Counter v-model="count" />- v-model использует modelValue как пропс и update:modelValue как событие.
- Требуется явно определять пропсы и эмитить события.
React: Пропсы и колбэк-функции
// Counter.jsx function Counter({ count, onCountChange }) { return ( <button onClick={() => onCountChange(count + 1)}> Увеличить </button> ); }// Родительский компонент const [count, setCount] = useState(0); <Counter count={count} onCountChange={setCount} />- React не имеет встроенной двусторонней привязки.
- Состояние обновляется через передачу функции onCountChange.
Реактивность и удобство
Svelte: Реактивность по умолчанию
- $bindable использует реактивную систему Svelte, где изменения переменной автоматически обновляют интерфейс.
- Минимум кода: let count = $bindable(0);
Vue: Явная реактивность
- Реактивность через ref, reactive, watch.
- Для v-model требуется передавать modelValue и эмитить события вручную.
React: Управление состоянием вручную
- Реактивность достигается через useState и useEffect.
- Для синхронизации нужно передавать состояние и функцию его обновления.
Фреймворк Метод Описание Svelte $bindableАвтоматически генерирует событие changeпри изменении значения. Реактивность встроена
- Минимальный код
- Автоматическая реактивность
- Доступен только в Svelte 5+
- Ограниченная поддержка сложных типов (объекты, массивы)Vue v-model+ событияИспользует propsиemitдля синхронизации. Требуется явное определение.
- Ясный API черезv-model
- Хорошо документирован
- Требуется вручную управлять событиями и пропсами
- Более многословный кодReact Пропсы и колбэки Полностью ручная реализация. Состояние обновляется через вызов функций.
- Полный контроль над состоянием
- Подходит для сложных приложений
- Нет встроенной двусторонней привязки
- Требует больше кода для простых задач -
$bindable— это специальная директива в Svelte 5+, которая позволяет помечать переменные как двухсторонне связуемые (bindable) в рамках компонента. Это означает, что вы можете использовать bind: на кастомных компонентах так же, как вы используете его, например, на нативном элементе<input bind:value>Ранее для этого требовалось писать отдельный механизм обработки событий (dispatch) и передачи значений обратно, но теперь всё это можно сделать с минимальным кодом благодаря $bindable.
Как работает $bindable
Когда вы пишете:
let count = $bindable(0);Вы создаёте реактивное свойство, которое:
- Реактивно обновляется при изменении локально.
- Автоматически генерирует событие change при изменении значения.
- Позволяет использовать bind: в родительском компоненте без дополнительного кода.
Под капотом
$bindableоборачивает значение в реактивную ссылку и подписывается на изменения, чтобы оповещать внешний мир через dispatch(‘change’, …). Таким образом, вы получаете прозрачный механизм двусторонней связи между компонентами.Сравнение с другими фреймворками
В современных фреймворках для работы с состоянием между компонентами используются разные подходы. В Svelte 5+ появился инструмент
$bindable, который упрощает создание двусторонних привязок. В Vue для этого традиционно используютv-modelи события, а в React — пропсы и колбэк-функции. Рассмотрим, как эти механизмы работают, их сходства и различия.Двухсторонняя привязка: $bindable (Svelte), v-model (Vue), props + callbacks (React)
Svelte: $bindable
<!-- Counter.svelte --> <script> let count = $bindable(0); </script> <button on:click={() => count += 1}>Увеличить</button><!-- Родительский компонент --> <Counter bind:count={myCount} />$bindableавтоматически генерирует событие change при изменении значения.- Родитель может использовать bind:propName для синхронизации.
Vue: v-model и события
<!-- Counter.vue --> <template> <button @click="increment">Увеличить</button> </template> <script setup> import { ref } from 'vue'; const props = defineProps(['modelValue']); const emit = defineEmits(['update:modelValue']); function increment() { emit('update:modelValue', props.modelValue + 1); } </script><!-- Родительский компонент --> <Counter v-model="count" />- v-model использует modelValue как пропс и update:modelValue как событие.
- Требуется явно определять пропсы и эмитить события.
React: Пропсы и колбэк-функции
// Counter.jsx function Counter({ count, onCountChange }) { return ( <button onClick={() => onCountChange(count + 1)}> Увеличить </button> ); }// Родительский компонент const [count, setCount] = useState(0); <Counter count={count} onCountChange={setCount} />- React не имеет встроенной двусторонней привязки.
- Состояние обновляется через передачу функции onCountChange.
Реактивность и удобство
Svelte: Реактивность по умолчанию
- $bindable использует реактивную систему Svelte, где изменения переменной автоматически обновляют интерфейс.
- Минимум кода: let count = $bindable(0);
Vue: Явная реактивность
- Реактивность через ref, reactive, watch.
- Для v-model требуется передавать modelValue и эмитить события вручную.
React: Управление состоянием вручную
- Реактивность достигается через useState и useEffect.
- Для синхронизации нужно передавать состояние и функцию его обновления.
Фреймворк Метод Описание Svelte $bindableАвтоматически генерирует событие changeпри изменении значения. Реактивность встроена
- Минимальный код
- Автоматическая реактивность
- Доступен только в Svelte 5+
- Ограниченная поддержка сложных типов (объекты, массивы)Vue v-model+ событияИспользует propsиemitдля синхронизации. Требуется явное определение.
- Ясный API черезv-model
- Хорошо документирован
- Требуется вручную управлять событиями и пропсами
- Более многословный кодReact Пропсы и колбэки Полностью ручная реализация. Состояние обновляется через вызов функций.
- Полный контроль над состоянием
- Подходит для сложных приложений
- Нет встроенной двусторонней привязки
- Требует больше кода для простых задач@Jspi Кажется пора прощаться с React

-

-
Bindable в Svelte — это, конечно, “вау, магия”, но давайте не будем забывать, что за эту магию кто-то платит.
Попробовал вчера переписать компонент с ручных dispatch на $bindable — вроде красиво, но как только начал кидать в пропсы вложенные объекты, всё посыпалось. Оказалось, Svelte не трекает изменения глубже первого уровня, и пришлось городить костыли с writable или ручным update().Сравнивать это с Vue/React — ну вы смелые. Там хоть понятно, где и как обновляется состояние, а тут “привязал и забыл” — пока не получишь баг, который воспроизводится только во время лунного затмения.

А кто-нибудь тестировал, как $bindable работает с SSR? У меня в SvelteKit компоненты начали падать при гидрации, когда привязки шли через пропсы. Пришлось откатывать на export let value и createEventDispatcher — зато теперь коллеги думают, что я гуру, который “не идёт на поводу у модных фич”.

P.S. Автор, спасибо за статью, но давайте честно: это же просто синтаксический сахар для ленивых, а не революция?
-
А правда, что директива $bindable должна использоваться редко? Говорят, что частое использование может усложнить отладку и снизить поддерживаемость кода. Или это просто пустые слова? Логично же, чтоеё использовапние вносит существенное упрощение в структуру кода. Почему тогда проблемы?
© 2024 - 2025 ExLends, Inc. Все права защищены.