В архитектуре Vue.js с использованием Vue Router и Vuex часто
возникает необходимость управлять маршрутизацией прямо из состояния
приложения, т.е. инициировать переходы по маршрутам из действий или
мутаций Vuex. Прямой доступ к объекту router в store не
предусмотрен по умолчанию, поэтому требуется корректная интеграция для
сохранения чистоты архитектуры и реактивности приложения.
router в storeСамый распространённый подход — передача экземпляра
router при инициализации store. Это позволяет действиям
Vuex вызывать маршруты без прямого импорта модуля router,
что сохраняет тестируемость и модульность кода.
Пример передачи router:
// router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About }
];
const router = createRouter({
history: createWebHistory(),
routes
});
export default router;
// store/index.js
import { createStore } from 'vuex';
export default function createMyStore(router) {
return createStore({
state: {
userLoggedIn: false
},
mutations: {
setLoginState(state, value) {
state.userLoggedIn = value;
}
},
actions: {
login({ commit }, { router }) {
commit('setLoginState', true);
router.push('/about');
}
}
});
}
При создании store необходимо передать объект
router:
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import createMyStore from './store';
const store = createMyStore(router);
createApp(App)
.use(store)
.use(router)
.mount('#app');
Ключевой момент: передача router при
инициализации делает его доступным в действиях store без глобальных
импортов, что облегчает тестирование и модульность.
rootState и rootGetters для маршрутизацииЕсли store модульный, доступ к router через отдельный модуль может
быть организован через rootState или
rootGetters. Например, можно хранить текущий маршрут в
состоянии и реагировать на его изменения.
const navigationModule = {
namespaced: true,
state: {
currentRoute: '/'
},
mutations: {
setRoute(state, route) {
state.currentRoute = route;
}
},
actions: {
navigate({ commit, rootState }, { path, router }) {
commit('setRoute', path);
router.push(path);
}
}
};
Такой подход позволяет отслеживать историю переходов в store и синхронизировать состояние интерфейса с маршрутизацией.
router через глобальный Vue объектВ Vue 3 можно использовать provide/inject для передачи экземпляра router в store. Например:
// main.js
import { createApp, provide } from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
const app = createApp(App);
app.provide('router', router);
app.use(store);
app.use(router);
app.mount('#app');
// store/actions.js
export function login({ commit }, { router }) {
commit('setLoginState', true);
router.push('/dashboard');
}
Этот метод особенно полезен, если store создается централизованно, а доступ к router требуется лишь в отдельных модулях.
Vuex позволяет выполнять асинхронные действия перед изменением маршрута. Это актуально для проверки прав пользователя или загрузки данных перед переходом.
Пример:
actions: {
async secureNavigate({ commit }, { router, path, checkAuth }) {
const isAuthorized = await checkAuth();
if (isAuthorized) {
router.push(path);
commit('setRoute', path);
} else {
router.push('/login');
}
}
}
Такой подход позволяет обрабатывать сложную логику перед сменой маршрута без нарушения реактивности компонентов.
При использовании TypeScript важно корректно типизировать
router в store:
import { Router } from 'vue-router';
interface ActionContextWithRouter {
commit: Function;
state: any;
router: Router;
}
const actions = {
login({ commit, router }: ActionContextWithRouter) {
commit('setLoginState', true);
router.push('/dashboard');
}
};
Типизация помогает избежать ошибок при работе с методами
router.push и router.replace и обеспечивает
автодополнение в редакторах.
router в состоянии Vuex
(state), чтобы не нарушать реактивность.router только в действия через аргументы или
при создании store.Эти подходы позволяют организовать чистую архитектуру взаимодействия Vuex и Vue Router, сохраняя модульность, реактивность и тестируемость приложения.