如何在Pinia action中正确使用GraphQL mutations实现登录
问题根源
你写的代码有4个核心错误,导致无法正常运行:
useMutation是Vue Apollo提供的组合式API,必须在Vue组件setup顶层、或者Pinia Store的初始化顶层调用,你把它写在login普通action内部,每次触发登录才执行调用,拿不到正确的Apollo客户端实例,本身就不符合组合式API的调用规则。- 你在action里只解构了
mutate方法和onDone回调,根本没有实际调用userLogin()触发登录请求,整个接口请求逻辑根本不会执行。 - Apollo的mutate操作是异步的,你在组件里调用完
authStore.login()就立刻执行路由跳转,此时登录请求还没返回,token还没写入本地和Store,跳转后会因为鉴权失败出问题。 - 你写的
useMutation传参存在语法错误,variables配置项的括号没有闭合。
可行修复方案
按照你的需求(登录逻辑全放Pinia action,组件内仅保留路由跳转),可以按下面的方式改:
1. 修正Pinia Store代码
把useMutation的初始化挪到Store顶层,将login action改为异步函数,用async/await控制请求流程,等token存储完成后再结束action逻辑:
import { defineStore } from 'pinia' import { ref } from 'vue' import { useMutation } from '@vue/apollo-composable' import { LOGIN_MUTATION } from '@/api/graphql/mutations' // 替换为你实际的mutation文件路径 export const useAuthStore = defineStore('auth', () => { // 登录表单状态 const formLogin = ref({ username: '', password: '' }) // token状态,初始化时优先读本地缓存 const accessToken = ref(localStorage.getItem('accessToken') || '') // 注意:useMutation必须在Store初始化顶层调用,不能放在action内部 const { mutate: loginMutate } = useMutation(LOGIN_MUTATION) // 异步登录action const login = async () => { try { // 等待登录请求返回结果 const res = await loginMutate({ variables: formLogin.value }) const token = res.data.login.token // 写入本地存储 localStorage.setItem('accessToken', token) // 写入全局状态 accessToken.value = token // 登录失败逻辑也可以全放这里,比如弹错误提示、重置表单 } catch (err) { console.error('登录失败:', err) throw err // 如果需要组件感知错误可以抛出,不需要的话直接在内部处理即可 } } return { formLogin, accessToken, login } })
2. 修正组件调用逻辑
组件内调用login action时加await,等所有登录逻辑执行完成、token存储完毕后再执行路由跳转:
<script setup> import { useAuthStore } from '@/stores/auth' import { useRouter } from 'vue-router' const authStore = useAuthStore() const router = useRouter() const loginUser = async () => { await authStore.login() // 组件内仅保留路由跳转逻辑,完全符合你的需求 router.push({ name: 'Home' }) } </script>
额外注意事项
- 所有
useXxx开头的组合式API,都必须在setup/Store初始化的顶层同步调用,不能放在普通函数、条件判断、循环中延迟执行,否则会丢失上下文导致报错。 - 相比
onDone回调的写法,直接awaitmutate返回值的异步控制方式更直观,不会出现时序错乱问题,逻辑更易维护。 - 如果需要做登录失败的交互(比如错误提示),直接把逻辑写在Pinia action的catch块里即可,组件不需要关心登录相关的任何业务逻辑。
内容的提问来源于stack exchange,提问作者netnull
相关产品推荐
相关产品推荐

