Адаптация навигационных хуков

Vue Router предоставляет мощную систему навигационных хуков, позволяющую контролировать переходы между маршрутами на различных уровнях приложения. Навигационные хуки делятся на глобальные, на уровне маршрута и на уровне компонента. Каждый из них имеет своё назначение и порядок вызова, что важно учитывать при построении сложной логики маршрутизации.


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

Глобальные хуки регистрируются на экземпляре маршрутизатора и отслеживают все переходы в приложении. Основные типы:

  1. beforeEach(to, from, next) Вызывается перед каждой навигацией. Используется для проверки прав доступа, аутентификации и выполнения подготовительных действий.

    • to – объект маршрута, к которому осуществляется переход

    • from – объект маршрута, с которого происходит переход

    • next – функция, определяющая дальнейший путь навигации:

      • next() – продолжить навигацию
      • next(false) – отменить переход
      • next('/path') – перенаправить на другой маршрут
  2. beforeResolve(to, from, next) Вызывается после beforeEach, но перед окончательной навигацией. Отличается тем, что уже доступны все асинхронные компоненты маршрута. Используется для динамической загрузки данных, необходимых перед отображением компонента.

  3. afterEach(to, from) Вызывается после завершения навигации. Не имеет аргумента next, так как навигация уже завершена. Подходит для аналитики, логирования или изменения состояния приложения после перехода.


Навигационные хуки на уровне маршрута

Каждый маршрут может содержать собственные хуки, определяемые в объекте маршрута:

const routes = [
  {
    path: '/dashboard',
    component: Dashboard,
    beforeEnter: (to, from, next) => {
      if (userIsAuthenticated()) {
        next();
      } else {
        next('/login');
      }
    }
  }
];
  • beforeEnter(to, from, next) – вызывается перед входом в конкретный маршрут. Отличие от глобальных хуков в том, что он срабатывает только для данного маршрута, позволяя локально контролировать доступ и выполняемые действия.

Навигационные хуки на уровне компонента

Компоненты маршрута могут определять следующие хуки:

  1. beforeRouteEnter(to, from, next) Вызывается перед рендерингом компонента. Особенность: компонент ещё не создан, поэтому доступ к this невозможен. Для работы с экземпляром компонента используется функция обратного вызова:
beforeRouteEnter(to, from, next) {
  next(vm => {
    vm.loadData();
  });
}
  1. beforeRouteUpdate(to, from, next) Срабатывает, когда текущий компонент остаётся тем же, но меняются параметры маршрута (params, query). Позволяет обновлять данные без полного уничтожения и повторного создания компонента.

  2. beforeRouteLeave(to, from, next) Вызывается перед уходом с маршрута, на котором находится компонент. Применяется для предупреждения пользователя о несохранённых данных или для отмены навигации при необходимости.


Порядок вызова хуков

Понимание порядка вызова критично для построения корректной логики:

  1. Глобальные beforeEach
  2. beforeEnter маршрута
  3. beforeRouteEnter компонентов
  4. beforeRouteUpdate компонентов (если маршрут обновляется, но компонент остаётся)
  5. beforeResolve глобальный
  6. afterEach глобальный

Этот порядок гарантирует, что глобальная логика выполняется до локальной, а финальные действия после успешного завершения навигации.


Асинхронная работа и промисы

Все хуки могут возвращать Promise вместо использования next(), что упрощает работу с асинхронными операциями:

router.beforeEach(async (to, from) => {
  const authorized = await checkUserAccess();
  if (!authorized) {
    return '/login';
  }
});

Возвращение строки маршрута или объекта { path: '/login' } заменяет вызов next() для перенаправления.


Практические рекомендации

  • Для проверки авторизации лучше использовать глобальный beforeEach, чтобы избежать дублирования кода на уровне маршрутов.
  • Хуки на уровне компонента подходят для управления данными и локальными эффектами, такими как подтверждение выхода.
  • Использование beforeResolve оптимально для предварительной загрузки асинхронных компонентов или данных перед отображением страницы.
  • Комбинируя хуки разных уровней, важно внимательно следить за последовательностью вызовов, чтобы не возникали конфликты при перенаправлениях.

Адаптация хуков под сложные сценарии

В больших приложениях часто возникает потребность адаптировать хуки под:

  • Динамическую маршрутизацию: добавление маршрутов на лету с проверкой прав доступа
  • Многоуровневые переходы: вложенные маршруты с вложенными компонентами, где каждый уровень имеет свои хуки
  • Асинхронные операции с загрузкой данных: использование Promise или async/await для гарантированного завершения перед навигацией

Пример обработки вложенного маршрута с асинхронной загрузкой данных:

const routes = [
  {
    path: '/projects/:id',
    component: ProjectLayout,
    beforeEnter: async (to) => {
      const project = await fetchProject(to.params.id);
      if (!project) return '/not-found';
    },
    children: [
      {
        path: 'overview',
        component: ProjectOverview
      },
      {
        path: 'tasks',
        component: ProjectTasks
      }
    ]
  }
];

Здесь beforeEnter проверяет существование проекта перед загрузкой дочерних маршрутов, предотвращая ненужные рендеры компонентов.