События компонентов через колбэки
Чтобы ребёнок сообщил родителю о событии, в Svelte 5 передают пропс-колбэк — обычную функцию.
«Событие — это когда ребёнок поднимает руку и кричит наверх: эй, родитель, кое-что случилось!»
Пропсы передают данные вниз. А как передать сигнал вверх — от ребёнка к родителю? Например, дочерняя кнопка нажата, и родитель должен это узнать. В Svelte 4 для этого был createEventDispatcher, но Svelte 5 упростил подход: события — это просто пропсы-колбэки. Родитель передаёт функцию вниз, ребёнок вызывает её, когда нужно.
Это та же модель, что и обычные DOM-обработчики, просто на уровне компонентов. И она прекрасно ложится в общую картину: всё — пропсы. Данные текут вниз как значения, события текут вверх как вызовы переданных функций.
<!-- LikeButton.svelte -->
<script>
let { onLike } = $props(); // колбэк от родителя
let count = $state(0);
function handle() {
count++;
onLike?.(count); // сообщаем наверх новое значение
}
</script>
<button onclick={handle}>Лайк ({count})</button>Родитель передаёт функцию через пропс с тем же именем:
<!-- родитель -->
<script>
import LikeButton from './LikeButton.svelte';
let likes = $state(0);
</script>
<LikeButton onLike={(n) => likes = n} />
<p>Всего лайков: {likes}</p>Когда пользователь нажимает кнопку внутри LikeButton, ребёнок вызывает onLike(count), и родитель обновляет своё состояние. Оператор ?. защищает на случай, если колбэк не передали. Заметьте, насколько это прозрачнее старого диспетчера событий — нет специального API, просто функции.
Как это работает под капотом
Колбэк-события — это паттерн «обратного вызова». Родитель владеет функцией, ребёнок её вызывает. Смоделируем на чистом JS.
// События как колбэки: ребёнок вызывает функцию родителя
function LikeButton({ onLike }) {
let count = 0;
return {
click() { count++; if (onLike) onLike(count); } // 'кричим наверх'
};
}
let likes = 0;
const child = LikeButton({ onLike: (n) => { likes = n; console.log('родитель узнал:', likes); } });
child.click(); // родитель узнал: 1
child.click(); // родитель узнал: 2Попробуй сам ▶ — вставь код в консоль браузера (F12 → Console) и нажми Enter, чтобы увидеть вывод.
Родитель Ребёнок (LikeButton)
-------- --------------------
onLike = (n) => likes = n --> получает как пропс
^ |
| вызов onLike(count) | клик по кнопке
+------------------------------+Частые ошибки
- Искать
createEventDispatcherв Svelte 5. Современный путь — колбэк-пропсы. - Вызывать колбэк без проверки. Используйте
onLike?.(), если пропс необязательный. - Пытаться мутировать пропс вместо вызова колбэка. Поток вверх — только через функции.
Best practices
- Называйте колбэки в стиле обработчиков:
onLike,onSubmit,onClose. - Передавайте наверх данные, а не реализацию: ребёнок сообщает «что случилось», родитель решает «что делать».
- Делайте колбэки необязательными там, где это уместно, и защищайте вызов
?..
Кто принимает решение
За паттерном колбэк-событий стоит важный принцип проектирования: ребёнок сообщает, что произошло, а решение, что с этим делать, принимает родитель. Кнопка лайка не знает, нужно ли отправить запрос на сервер, обновить счётчик в шапке или показать анимацию — она лишь кричит наверх «меня нажали». Это держит компоненты слабо связанными и переиспользуемыми: одну и ту же кнопку можно вставить в десяток мест, и в каждом родитель навесит свою реакцию. Старайтесь передавать наверх минимальные осмысленные данные — что случилось и с какими параметрами, — а не готовые действия. Тогда дочерний компонент остаётся универсальным, а вся специфичная логика концентрируется в родителе, который владеет контекстом. Этот разделённый поток — данные вниз, события вверх — образует ясную, предсказуемую архитектуру, в которой легко проследить, откуда взялось любое изменение состояния.
Итог: в Svelte 5 события — это пропсы-функции. Ребёнок вызывает переданный колбэк, родитель реагирует. Никакого специального API — данные вниз, вызовы вверх.