You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue.js中提交表单前如何更新响应式变量me?

问题分析

你的代码核心问题在于逻辑顺序完全颠倒:在调用登录接口login之前就判断me.value === null,此时用户还未发起登录请求,me必然是初始的null值,所以错误弹窗会每次都触发;同时在handleSubmit内部创建watchEffect会导致每次提交都新增一个监听,容易引发内存泄漏和重复逻辑。

修正方案

关键调整思路

  1. 先执行登录请求,再根据登录结果处理后续操作
  2. 登录成功后主动刷新用户信息me(如果useMe是基于查询库实现,通常会提供refetch方法)
  3. 监听me的变化,确保用户信息更新后再执行跳转或错误提示

修改后的完整代码

<script setup lang="ts">
import { NButton, NCard, NForm, NFormItem, NInput, NSpace, useDialog } from 'naive-ui';
import { useLogin } from '@/composables/API/useLogin';
import { computed, ref, watch } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { useMe } from '@/composables/API/useMe';
import { useI18n } from 'vue-i18n';

const { mutate: login } = useLogin();
const credentials = ref({ username: '', password: '' });
// 解构出refetch方法,用于登录后主动刷新用户信息
const { data: me, refetch } = useMe();
const { t } = useI18n({ useScope: 'global' });
const dialog = useDialog();
const router = useRouter();
const route = useRoute();
const redirectRoute = computed(() => {
  const redirect = route.query.returnUrl;
  if (redirect) {
    return redirect as string;
  }
  return '/';
});

// 监听me的变化,处理登录后的最终结果
const unwatchMe = watch(me, (newMe) => {
  if (newMe === null) {
    dialog.error({
      title: t('login.errorPopup.title'),
      content: t('login.errorPopup.content'),
      positiveText: t('login.errorPopup.positiveText'),
    });
    // 触发一次后取消监听,避免后续重复触发
    unwatchMe();
  } else {
    router.replace(redirectRoute.value);
    unwatchMe();
  }
}, { immediate: false });

const handleSubmit = () => {
  const { username, password } = credentials.value;
  // 简化表单非空验证
  if (!username || !password) return;

  login(credentials.value, {
    onSuccess: () => {
      // 登录接口请求成功后,主动刷新用户信息
      refetch();
    },
    onError: () => {
      // 登录接口本身请求失败时直接弹窗提示
      dialog.error({
        title: t('login.errorPopup.title'),
        content: t('login.errorPopup.content'),
        positiveText: t('login.errorPopup.positiveText'),
      });
    }
  });
};
</script>

<template>
  <n-space vertical justify="center" align="center" :size="20" style="width: 100vw; height: 100vh">
    <img alt="GPI logo" src="@/assets/logo.svg" style="width: 200px" />
    <n-card :title="$t('login.title')" size="huge" embedded style="width: 400px">
      <n-form
        :model="credentials"
        @submit.prevent="handleSubmit"
        label-placement="left"
        label-width="auto"
        label-align="left"
      >
        <n-form-item :label="$t('login.username')" path="username">
          <n-input v-model:value="credentials.username" :placeholder="$t('login.username')" />
        </n-form-item>
        <n-form-item :label="$t('login.password')" path="password">
          <n-input
            v-model:value="credentials.password"
            type="password"
            show-password-on="mousedown"
            :placeholder="$t('login.password')"
          />
        </n-form-item>
        <n-form-item>
          <n-button attr-type="submit" type="primary" block>{{ $t('login.submit') }}</n-button>
        </n-form-item>
      </n-form>
    </n-card>
  </n-space>
</template>

核心修改说明

  • 移除handleSubmit内部的watchEffect,改为组件初始化时创建一次性监听,避免重复监听导致的逻辑混乱
  • 登录成功后调用refetch()强制刷新me,确保用户信息及时更新
  • 拆分错误处理逻辑:区分登录接口请求失败(onError回调)和用户信息获取失败(watch监听me为null)
  • 简化表单非空验证逻辑,代码更简洁

如果你的useMe不是基于查询库实现的,无法使用refetch,可以在login的onSuccess回调中手动触发用户信息的获取接口,确保me被正确更新后再执行后续操作。

内容的提问来源于stack exchange,提问作者rocco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 17:43:08