Hyperapp использует подписки для реагирования на внешние события, такие как таймеры, веб-сокеты, события клавиатуры или изменения состояния в браузере. Подписки позволяют отделить логику приложения от побочных эффектов и поддерживать архитектуру реактивного типа без сложных библиотек управления состоянием.
Подписка — это функция, которая возвращает функцию отписки. Она принимает объект с текущим состоянием и объект действий, а затем подключается к внешнему источнику событий. Когда события происходят, подписка вызывает соответствующие действия.
const mySubscription = (state, actions) => {
const interval = setInterval(() => {
actions.tick(Date.now());
}, 1000);
return () => clearInterval(interval);
};
В этом примере создается таймер, который каждую секунду вызывает
действие tick. Возвращаемая функция
clearInterval используется Hyperapp для корректного
отключения подписки при размонтировании компонента или изменении
состояния, вызывающем пересоздание подписок.
Подписки подключаются через ключ subscriptions при
инициализации приложения:
import { app } from "hyperapp";
const state = { time: Date.now() };
const actions = {
tick: (time) => ({ time })
};
const subscriptions = (state) => [mySubscription];
app({ state, actions, view, subscriptions });
Функция subscriptions вызывается каждый раз при
изменении состояния. Это позволяет динамически включать и отключать
подписки в зависимости от текущего состояния приложения.
Подписки можно делать динамическими, возвращая разные наборы функций в зависимости от состояния:
const subscriptions = (state) =>
state.isActive ? [activeSubscription] : [inactiveSubscription];
Такой подход позволяет оптимизировать приложение, отключая ненужные подписки и предотвращая утечки памяти.
Подписки могут принимать аргументы, чтобы быть более универсальными:
const keyPressSubscription = (key, action) => (state, actions) => {
const handler = (event) => {
if (event.key === key) action(event);
};
window.addEventListener("keydown", handler);
return () => window.removeEventListener("keydown", handler);
};
const subscriptions = () => [
keyPressSubscription("Enter", (event) => console.log("Enter pressed"))
];
Этот подход позволяет создавать подписки, которые реагируют на конкретные события и вызывают нужные действия.
Hyperapp поддерживает массивы подписок, что позволяет комбинировать различные источники событий:
const subscriptions = (state) => [
timerSubscription,
mouseMoveSubscription,
websocketSubscription
];
Каждая подписка создается независимо и возвращает свою функцию отписки. Hyperapp автоматически управляет подключением и отключением всех подписок при изменениях состояния.
Ключевой аспект подписок — корректная отписка для предотвращения утечек памяти. Каждая подписка должна возвращать функцию очистки ресурсов. Hyperapp вызывает эту функцию каждый раз, когда подписка перестает быть актуальной:
const mouseMoveSubscription = (state, actions) => {
const handler = (e) => actions.updateMouse({ x: e.clientX, y: e.clientY });
window.addEventListener("mousemove", handler);
return () => window.removeEventListener("mousemove", handler);
};
Без такой функции приложение может накапливать слушатели событий и потреблять всё больше памяти при длительной работе.
Подписки можно использовать для интеграции с асинхронными источниками, такими как веб-сокеты, таймауты или fetch-запросы:
const websocketSubscription = (state, actions) => {
const socket = new WebSocket("wss://example.com/socket");
socket.addEventListener("message", (event) => {
actions.receiveMessage(JSON.parse(event.data));
});
return () => socket.close();
};
Использование подписок для асинхронных операций позволяет разделить побочные эффекты и логику изменения состояния, делая код более управляемым и тестируемым.
Подписки являются мощным инструментом Hyperapp, обеспечивающим реактивность и контроль внешних событий. Они позволяют создавать интерактивные приложения, поддерживать актуальное состояние и аккуратно управлять ресурсами.