Создание пользовательских подписок

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, обеспечивающим реактивность и контроль внешних событий. Они позволяют создавать интерактивные приложения, поддерживать актуальное состояние и аккуратно управлять ресурсами.