Хуки before и after

В библиотеке Universal Router хуки before и after предоставляют мощный механизм для управления поведением маршрутов до и после их обработки. Эти хуки позволяют внедрять общую логику в маршруты, не дублируя код в каждом обработчике. Они особенно полезны для авторизации, логирования, обработки ошибок, отслеживания переходов и асинхронных операций.


Хук before

Хук before вызывается перед обработкой маршрута, и его задача — определить, может ли маршрут быть выполнен, или изменить контекст выполнения. Он принимает два параметра:

before(context, next)
  • context — объект текущего контекста маршрута, содержащий pathname, query, params, route и другие свойства.
  • next — функция, вызывающая следующий шаг маршрутизации. Она может быть синхронной или возвращать Promise.

Основные сценарии использования

  1. Авторизация и защита маршрутов
const router = new UniversalRouter(routes, {
  before: async (context, next) => {
    if (context.pathname.startsWith('/admin')) {
      const user = await getUser();
      if (!user.isAdmin) {
        return '/login';
      }
    }
    return next();
  }
});

В этом примере любой переход к /admin проверяется на права администратора. Если проверка не проходит, происходит редирект на /login.

  1. Модификация контекста маршрута
before: (context, next) => {
  context.startTime = Date.now();
  return next();
}

Добавление временной метки позволяет замерять производительность маршрута в хуке after.

  1. Асинхронная подготовка данных
before: async (context, next) => {
  context.userData = await fetchUserData();
  return next();
}

Все обработчики маршрута получают заранее подготовленные данные, что упрощает архитектуру приложения.

Возврат значений

  • next() — продолжить выполнение маршрута.
  • Любое другое значение (строка, объект, компонент) — прекращает дальнейшее выполнение и возвращает это значение как результат маршрута.
  • Promise — позволяет использовать асинхронные проверки и подгрузку данных.

Хук after

Хук after вызывается после того, как маршрут был обработан и результат маршрута сформирован. Он позволяет модифицировать результат или выполнить побочные эффекты. Сигнатура:

after(context, result)
  • context — тот же объект, что и в хуке before.
  • result — результат выполнения маршрута (строка, объект, React-компонент и т.д.).

Основные сценарии использования

  1. Логирование и аналитика
after: (context, result) => {
  console.log(`Маршрут ${context.pathname} завершен с результатом:`, result);
  return result;
}

С помощью этого подхода можно отслеживать успешные и неуспешные переходы в приложении.

  1. Измерение времени выполнения
after: (context, result) => {
  const duration = Date.now() - context.startTime;
  console.log(`Время выполнения маршрута: ${duration}ms`);
  return result;
}

Хук after идеально подходит для профилирования и оптимизации.

  1. Постобработка результатов
after: (context, result) => {
  if (typeof result === 'string') {
    return result.toUpperCase();
  }
  return result;
}

Позволяет изменять результат маршрута перед его отображением или отправкой пользователю.


Глобальные и локальные хуки

  • Глобальные хуки задаются при создании экземпляра маршрутизатора и применяются ко всем маршрутам:
const router = new UniversalRouter(routes, {
  before: globalBeforeHook,
  after: globalAfterHook
});
  • Локальные хуки определяются для отдельного маршрута в конфигурации:
{
  path: '/profile',
  action: () => 'Profile Page',
  before: (ctx, next) => { /* локальная проверка */ return next(); },
  after: (ctx, result) => { /* локальная обработка результата */ return result; }
}

Логика выполнения: сначала вызываются глобальные хуки, затем локальные.


Особенности работы с асинхронностью

Хуки before и after полностью поддерживают Promise. Если внутри before вызывается асинхронная операция, Universal Router дождется её завершения:

before: async (context, next) => {
  const allowed = await checkAccess(context.user);
  if (!allowed) return '/403';
  return next();
}

Хук after также может быть асинхронным, например, для записи логов на сервер:

after: async (context, result) => {
  await sendAnalytics(context.pathname, result);
  return result;
}

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

  • Хук before может полностью прервать выполнение маршрута, возвращая новый путь или результат.
  • Хук after не влияет на переход, только на результат.
  • Ошибки, выброшенные внутри хуков, автоматически прокидываются и могут быть обработаны через try/catch или глобальные обработчики ошибок маршрутизатора.
  • context является единым объектом для всех хуков и обработчиков маршрута, что позволяет передавать данные между before, action и after.

Рекомендации по использованию

  • Использовать before для проверок, авторизации, подгрузки данных и редиректов.
  • Использовать after для логирования, аналитики, модификации результатов и выполнения побочных эффектов.
  • Комбинировать глобальные и локальные хуки для максимальной гибкости.
  • Всегда учитывать асинхронность и корректно возвращать Promise, чтобы избежать неконсистентного поведения.

Хуки before и after создают универсальный инструмент для контроля маршрутов и позволяют выстраивать чистую архитектуру приложения, делая маршрутизатор гибким, безопасным и легко расширяемым.