Hyperapp использует концепцию подписок (subscriptions) для реагирования на внешние события, которые происходят вне потока обновления состояния приложения. Подписки позволяют связать состояние приложения с внешними источниками данных, такими как таймеры, WebSocket, события DOM или API.
Подписки не изменяют напрямую состояние приложения. Вместо этого они отправляют действия (actions), которые обновляют состояние через стандартный поток Hyperapp: состояние → view → action → новое состояние.
Подписки задаются в корневой функции app в объекте
subscriptions. Каждая подписка — это функция, принимающая
текущее состояние и возвращающая функцию, которая вызывает переданные
действия.
Простейший пример подписки:
import { app, h } from "https://unpkg.com/hyperapp?module";
const state = { count: 0 };
const actions = {
increment: () => state => ({ count: state.count + 1 })
};
const subscriptions = state => [
(dispatch) => {
const interval = setInterval(() => dispatch(actions.increment), 1000);
return () => clearInterval(interval);
}
];
app({ state, actions, view: state => h("div", {}, state.count), subscriptions });
Разбор:
dispatch как аргумент.setInterval).Подписки позволяют обновлять состояние через равные промежутки времени. Пример выше показывает автоматическое увеличение счетчика каждую секунду.
Подписки могут слушать события на элементах, которые создаются вне Hyperapp:
const subscriptions = () => [
(dispatch) => {
const handleClick = () => dispatch(actions.increment);
document.addEventListener("click", handleClick);
return () => document.removeEventListener("click", handleClick);
}
];
Подписки идеально подходят для подписки на внешние потоки данных. Например:
const subscriptions = () => [
(dispatch) => {
const ws = new WebSocket("wss://example.com/socket");
ws.onmess age = event => dispatch(actions.updateData(JSON.parse(event.data)));
return () => ws.close();
}
];
Hyperapp гарантирует вызов функции очистки для каждой подписки при изменении состояния, если подписка больше не нужна. Это важно для:
Пример с динамическими подписками:
const state = { enabled: true };
const actions = {
toggle: () => state => ({ enabled: !state.enabled }),
increment: () => state => ({ count: (state.count || 0) + 1 })
};
const subscriptions = state => state.enabled ? [
dispatch => {
const interval = setInterval(() => dispatch(actions.increment), 1000);
return () => clearInterval(interval);
}
] : [];
При переключении enabled на false
предыдущий интервал автоматически очищается.
Подписки используют dispatch для вызова действий.
Actions могут быть синхронными или асинхронными. Асинхронные действия
особенно полезны при работе с внешними API:
const actions = {
fetchData: () => async state => {
const response = await fetch("https://api.example.com/data");
const data = await response.json();
return { data };
}
};
const subscriptions = () => [
dispatch => {
const timer = setInterval(() => dispatch(actions.fetchData), 5000);
return () => clearInterval(timer);
}
];
Таким образом, подписки предоставляют интерфейс между внешним миром и потоками действий Hyperapp, сохраняя чистоту архитектуры и предсказуемость состояния.
Механизм подписок делает Hyperapp подходящим для создания реактивных приложений с минимальным и управляемым кодом, обеспечивая контроль над внешними событиями и асинхронными потоками данных.