Отписка от событий

В Page.js управление событиями маршрутизации строится на цепочке middleware-функций, которые вызываются при совпадении текущего URL с заданным маршрутом. Каждая функция получает объект ctx (контекст запроса) и next — функцию для передачи управления следующему обработчику. Для корректного управления подписками важно понимать, как происходит регистрация и отписка этих функций.


Регистрация обработчиков

Простейший способ добавить обработчик маршрута:

page('/about', (ctx, next) => {
    console.log('Переход на страницу About');
    next();
});

Здесь (ctx, next) автоматически подписывается на изменение URL, и при каждом совпадении маршрута функция вызывается. Все зарегистрированные функции накапливаются в глобальной цепочке middleware.

Если не организовать отписку, старые функции будут вызываться каждый раз при переходе, что может привести к утечкам памяти и неожиданным побочным эффектам.


Принципы отписки

Page.js не предоставляет встроенного метода off для удаления конкретного middleware после регистрации. Управление подпиской осуществляется через самостоятельное создание контролируемых функций, которые можно включать или отключать по событию.

  1. Использование обёртки с флагом активности
let active = true;

function aboutHandler(ctx, next) {
    if (!active) return next();
    console.log('Переход на About активен');
    next();
}

page('/about', aboutHandler);

// Позже
active = false; // Функция больше не выполняет логику

Такой подход позволяет “отключить” обработчик, не удаляя его из цепочки middleware.

  1. Динамическая регистрация и удаление через функции-обёртки
function createHandler() {
    const handler = (ctx, next) => {
        console.log('Активный обработчик');
        next();
    };
    page('/dynamic', handler);
    return () => {
        // Для отписки просто заменяем на noop
        page('/dynamic', (ctx, next) => next());
    };
}

const unsubscribe = createHandler();

// Вызов при необходимости отключения
unsubscribe();

Этот метод особенно полезен при работе с компонентами SPA, которые монтируются и размонтируются динамически.


Очистка глобальных слушателей

Page.js опирается на события popstate и click для управления историей. При полном завершении работы приложения или при повторной инициализации маршрутов нужно корректно очищать слушатели:

page.stop(); // Убирает все текущие маршруты и слушатели событий

После вызова page.stop() можно заново настроить маршруты, не опасаясь, что старые обработчики будут срабатывать.


Примеры реальных сценариев отписки

1. SPA-компоненты с жизненным циклом

function mountComponent() {
    let active = true;

    function handler(ctx, next) {
        if (!active) return next();
        console.log('Компонент активен на маршруте', ctx.path);
        next();
    }

    page('/component', handler);

    return () => active = false; // отписка при размонтировании
}

const unsubscribe = mountComponent();

// позже
unsubscribe(); // компонент размонтирован, обработчик отключен

2. Временные маршруты для уведомлений

function showNotificationRoute() {
    const tempHandler = (ctx, next) => {
        alert('Временное уведомление');
        next();
    };

    page('/notify', tempHandler);

    // Автоматическая отписка через 5 секунд
    setTimeout(() => {
        page('/notify', (ctx, next) => next());
    }, 5000);
}

Важные нюансы

  • Отписка через замену обработчика на next() не удаляет его из массива middleware, но предотвращает выполнение логики.
  • Полное удаление всех подписок достигается только через page.stop().
  • Для динамических компонентов рекомендуется хранить ссылки на функции для контроля их состояния.
  • Использование флага active предпочтительнее при частых переходах, так как избегает создания новых функций в цепочке.

Рекомендации по организации кода

  • Разделять маршруты и обработчики по компонентам или модулям.
  • Всегда предусматривать жизненный цикл middleware для SPA.
  • Для временных или динамических маршрутов применять обёртки с unsubscribe.
  • Использовать page.stop() при полной очистке маршрутов перед повторной инициализацией.

Эти практики обеспечивают управляемость цепочки middleware и предотвращают накопление “мертвых” обработчиков, что критично для производительных и стабильных приложений на Page.js.