Vue3+Vue Router4导航守卫致Pinia中router.push报错undefined
解决Vue 3 + Pinia + Vue Router 4中router.push() undefined错误
问题描述
在Vue 3项目中使用Vue Router 4的导航守卫时,Pinia store里的router.push('/')和router.push({ name: "login" })均出现undefined错误,代码执行时抛出Cannot read properties of undefined (reading 'push')异常。相关代码及错误截图如下:
路由文件代码
import { createRouter, createWebHistory } from "vue-router"; import manageStaffRoutes from "./manage.staff.js"; import authRoutes from "./login.js"; import { useAuthStore } from "@/stores/auth.store.js"; const routes = [...manageStaffRoutes, ...authRoutes]; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes, }); router.beforeEach(async (to, from) => { const auth = await useAuthStore(); const publicPages = ["/login", "/super-admin-login"]; const authRequired = !publicPages.includes(to.path); if (authRequired && !auth.user) { return "/"; } }); export default router;
Pinia store代码
import { defineStore } from "pinia"; import { ref, computed } from "vue"; import axios from "axios"; import { useRouter } from "vue-router"; export const useAuthStore = defineStore("userAuth", () => { const router = useRouter(); const userData = ref(null); const errorMessages = ref(null); const user = computed(() => { return JSON.parse(localStorage.getItem("user")); }); if (user.value) { axios.defaults.headers.common["Authorization"] = `${user.value.token}`; } async function login(email, password) { try { const data = await axios.post("api/v1/users/login", { email: email, password: password, }); if (data.status === 200) { userData.value = data.data; localStorage.setItem( "user", JSON.stringify(userData.value.data) ); await router.push("/"); // 报错位置 } } catch (error) { console.log(error); return (errorMessages.value = error.response.data.errorsToSend); } } const logout = async () => { try { const data = await axios.post("api/v1/users/logout"); console.log(data); if (data.status === 201) { user.value = null; localStorage.removeItem("user"); await router.push({ name: "login" }); // 报错位置 } } catch (error) { console.log(error); // return (errorMessages.value = error.response.data.message); } }; return { login, user, errorMessages, logout }; });
错误截图

错误原因
- Pinia store中过早调用useRouter():
useRouter()是Vue Router提供的组合式函数,需要在Vue的响应式上下文(如组件setup、钩子函数或Pinia action内部)中调用。而在store的顶层(defineStore回调的根级别)调用时,Vue Router实例尚未被注入到应用中,导致返回undefined。 - 路由守卫中错误使用useAuthStore:
useAuthStore()是同步创建store实例的函数,不需要用await修饰;同时未授权时跳转到"/"会触发导航守卫循环重定向,逻辑错误。 - logout方法中错误修改computed属性:
user是基于localStorage的computed属性,直接赋值user.value = null无效,因为computed是只读的。
解决方案
1. 修正Pinia store中router的获取方式
将useRouter()移到login和logout方法内部,确保在Vue上下文环境中调用:
import { defineStore } from "pinia"; import { ref, computed } from "vue"; import axios from "axios"; import { useRouter } from "vue-router"; export const useAuthStore = defineStore("userAuth", () => { const userData = ref(null); const errorMessages = ref(null); const user = computed(() => { return JSON.parse(localStorage.getItem("user")); }); if (user.value) { axios.defaults.headers.common["Authorization"] = `${user.value.token}`; } async function login(email, password) { const router = useRouter(); // 移到方法内部 try { const data = await axios.post("api/v1/users/login", { email: email, password: password, }); if (data.status === 200) { userData.value = data.data; localStorage.setItem( "user", JSON.stringify(userData.value.data) ); // 更新请求头 axios.defaults.headers.common["Authorization"] = `${userData.value.data.token}`; await router.push("/"); } } catch (error) { console.log(error); errorMessages.value = error.response?.data?.errorsToSend || '登录失败'; } } const logout = async () => { const router = useRouter(); // 移到方法内部 try { const data = await axios.post("api/v1/users/logout"); console.log(data); if (data.status === 201) { localStorage.removeItem("user"); delete axios.defaults.headers.common["Authorization"]; await router.push({ name: "login" }); } } catch (error) { console.log(error); } }; return { login, user, errorMessages, logout }; });
2. 修正路由守卫逻辑
移除useAuthStore前的await,修改未授权时的跳转目标为登录页,避免循环重定向:
import { createRouter, createWebHistory } from "vue-router"; import manageStaffRoutes from "./manage.staff.js"; import authRoutes from "./login.js"; import { useAuthStore } from "@/stores/auth.store.js"; const routes = [...manageStaffRoutes, ...authRoutes]; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes, }); router.beforeEach((to, from) => { const auth = useAuthStore(); // 移除await const publicPages = ["/login", "/super-admin-login"]; const authRequired = !publicPages.includes(to.path); if (authRequired && !auth.user) { return "/login"; // 跳转到登录页而非主页 } }); export default router;
关键修改点说明
- router实例获取时机:在action内部调用
useRouter(),确保处于Vue响应式上下文,能正确获取路由实例。 - 导航守卫逻辑:同步获取store实例,修正跳转目标避免循环重定向。
- computed属性操作:通过修改localStorage来更新user的computed值,而非直接赋值computed属性;同时清理axios请求头,避免无效授权。
内容的提问来源于stack exchange,提问作者Franz Schad
相关产品推荐
相关产品推荐

