Навигация из actions

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


Доступ к экземпляру маршрутизатора

В Vue 3 с использованием Composition API доступ к маршрутизатору осуществляется через функцию useRouter. В Vuex или Pinia actions не имеют прямого доступа к экземпляру маршрутизатора, поэтому его нужно передавать явно или импортировать.

Пример передачи роутера в action:

// store.js
export const useStore = defineStore('main', {
  actions: {
    async login(userData, router) {
      const response = await api.login(userData);
      if (response.success) {
        router.push({ name: 'dashboard' });
      }
    }
  }
});

В этом примере роутер передается как аргумент в action, что позволяет управлять переходами внутри логики хранилища.


Программная навигация

Vue Router поддерживает несколько способов программного перехода:

  1. Метод push – добавляет новый маршрут в историю браузера.
  2. Метод replace – заменяет текущий маршрут, не создавая новую запись в истории.
  3. Метод go – перемещает пользователя на указанное количество шагов в истории.

Примеры использования в action:

actions: {
  navigateToProfile(router, userId) {
    router.push({ name: 'profile', params: { id: userId } });
  },
  navigateToHome(router) {
    router.replace({ path: '/' });
  }
}

Ключевые моменты:

  • push подходит для обычных переходов, когда важно сохранить возможность возвращения назад.
  • replace используется для переходов после действий, где возврат к предыдущему маршруту нежелателен (например, после успешного логина).

Навигация с query-параметрами и hash

Программный переход позволяет передавать дополнительные данные через query-параметры или hash. Это особенно полезно для фильтрации данных или сохранения состояния страницы.

actions: {
  filterProducts(router, category) {
    router.push({ 
      name: 'products', 
      query: { category } 
    });
  },
  scrollToSection(router, sectionId) {
    router.push({ 
      path: '/home', 
      hash: `#${sectionId}` 
    });
  }
}

Особенности работы с query и hash:

  • Query-параметры остаются в адресной строке и могут быть прочитаны в компоненте через route.query.
  • Hash позволяет скроллить к конкретному элементу страницы, если настроено поведение scrollBehavior в роутере.

Обработка ошибок навигации

Методы push и replace возвращают промис, что позволяет обрабатывать возможные ошибки, например, при попытке перехода на текущий маршрут:

actions: {
  safeNavigate(router, route) {
    router.push(route).catch(err => {
      if (err.name !== 'NavigationDuplicated') {
        console.error('Ошибка навигации:', err);
      }
    });
  }
}

Это предотвращает выброс ненужных ошибок при повторном переходе на тот же маршрут.


Навигация после асинхронных действий

Часто необходимо выполнить навигацию после успешного запроса к API. Использование async/await в actions обеспечивает последовательное выполнение:

actions: {
  async submitForm(router, formData) {
    try {
      const result = await api.submit(formData);
      if (result.success) {
        router.push({ name: 'thankYou' });
      }
    } catch (error) {
      console.error('Ошибка при отправке формы:', error);
    }
  }
}

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


Интеграция с Pinia

В Pinia actions полностью поддерживают работу с Vue Router, и подход передачи роутера аналогичен Vuex:

import { defineStore } from 'pinia';

export const useUserStore = defineStore('user', {
  actions: {
    logout(router) {
      this.user = null;
      router.replace({ name: 'login' });
    }
  }
});

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


Использование навигации в Composition API

При использовании Composition API можно напрямую импортировать роутер через useRouter внутри функций, вызываемых из actions:

import { useRouter } from 'vue-router';

export function useAuthActions(store) {
  const router = useRouter();

  async function login(userData) {
    const res = await api.login(userData);
    if (res.success) {
      router.push({ name: 'dashboard' });
    }
  }

  return { login };
}

Такой подход позволяет избежать передачи роутера через аргументы и упрощает взаимодействие между store и компонентами.