如果从 onMounted 钩子引用,Pinia 存储包含空值

问题描述 投票:0回答:1

我遇到一个问题,如果我尝试通过

null
钩子访问它,我的 Pinia 商店将包含其每个状态属性的
onMounted
。实际情况比这稍微复杂一些。这是基本上的调用堆栈

  • 组件(OnMounted)调用
  • 可组合调用
  • Pinia 商店

组件

onMounted(async () => {
    const resp = await $authFetch(config.functionsBaseUrl + 'v1/account/settings',
    {
        method: 'GET'
    }).catch(e => {
        toast.show({
            type: 'error',
            title: 'Error',
            content: e.data
        });

        return null;
    })

    if (resp === null)
    return;

    userSetings.value = resp;
})

可组合

export async function $authFetch<T>(
    request: Parameters<typeof $fetch<T>>[0],
    opts?: Parameters<typeof $fetch<T>>[1],
) {
    const auth = useAuth(useNuxtApp().$pinia);

    const shouldRefreshToken = () => {
        const currentTime = Math.floor(Date.now() / 1000);

        // Calculate the time difference between expiration time and current time
        console.log('calculating', auth.tokenExpiration);
        const timeDifference = auth.tokenExpiration - currentTime;
        console.log('time diff', timeDifference);
        // Check if the token is expiring within the next 5 minutes (300 seconds)
        return timeDifference <= 300;
    }

    console.log('authFetch', auth, auth.tokenExpiration, shouldRefreshToken());

    if (auth.tokenExpiration && shouldRefreshToken()) {
        const url = useRuntimeConfig().public.functionsBaseUrl + 'v1/auth/refresh';
        console.log('refreshing', url);
        const resp = await $fetch(url, {
            method: 'POST',
            body: {
                refreshToken: auth.refreshToken,
                idToken: auth.token
            },
            headers: {
                Authorization: `Bearer ${auth.token}`
            }
        }).catch(e => {
            if (e.data === 'Unauthorized') {
                //refresh token has expired, log the user out
                auth.$reset();
                const cookie = useCookie('auth');
                cookie.value = null;
            }
        });

        auth.token = resp.Token;
        auth.tokenExpiration = resp.Expiration;
    }

    return $fetch<T>(request, {
        ...opts,
        headers: {
            Authorization: `Bearer ${auth.token}`,
            ...opts?.headers,
        },
    });
}

商店

export const useAuth = defineStore('auth', {
    state: () => ({
        token: null,
        refreshToken: null,
        email: null,
        userId: null,
        firstName: null,
        lastName: null,
        organizationId: null,
        organizationName: null,
        organizationIndustry: null,
        tokenExpiration: null
    }),
    actions: {
        setLoginPayload(loginResponse) {
            this.token = loginResponse.Token;
            this.refreshToken = loginResponse.RefreshToken;
            this.email = loginResponse.Email;
            this.userId = loginResponse.UserId;
            this.firstName = loginResponse.FirstName;
            this.lastName = loginResponse.LastName;
            this.organizationId = loginResponse.OrganizationId;
            this.organizationName = loginResponse.CompanyName;
            this.organizationIndustry = loginResponse.Industry;
            this.tokenExpiration = loginResponse.Expiration;
            console.log('set token expiration', loginResponse.Expiration);

            //set in localstorage
            const cookie = useCookie('auth');
            cookie.value = loginResponse;
        }
    }
})

如果我在 1 秒的延迟内将代码包装在 onMounted 函数中,则存储值不再为空

我在任何地方都找不到任何东西可以解释 Pinia 需要一些时间来“准备好”或等待它“准备好”的方法

这里有什么明显的原因为什么我的商店在调用 onMount 时是空的吗?

编辑1 为了清楚起见,我展示了实际设置商店的代码。 登录后..

login.vue

const login = async () => {
  loggingIn.value = true;
  var url = useRuntimeConfig().public.functionsBaseUrl + "v1/auth/login";
  var response = await $fetch(url, {
    method: 'POST',
    body: {
      email: email.value,
      password: password.value
    }
  }).catch(error => {
    console.log(error);
    toast.show({
      title: 'Login Error',
      content: error.data,
      type: 'error',
      timeout: 5000
    })

    loggingIn.value = false;
  });

  if (response) {
    auth.setLoginPayload(response);
    toast.show({
      content: `Welcome ${auth.firstName}!`,
      type: 'success',
      title: 'Success'
    });

    const router = useRouter();

    setTimeout(() => {
      router.push('/documents');
    }, 1000);
  }
};

如果用户刷新浏览器

app.vue

onMounted(() => {
  const jsonAuth = useCookie('auth');
  console.log('jsonauth', jsonAuth.value);
  //keep the user logged in
  //TODO, figure out what happens once the refresh token expires. at this point the refresh mechanism will no longer work,
  //we need a way to detect this and send the user to the login screen
  if (jsonAuth.value) {
    const auth = useAuth();
    auth.setLoginPayload(jsonAuth.value);
  }

})
nuxt.js nuxt3.js pinia
1个回答
0
投票

想通了。当然,如果不知道 Nuxt3/Vue3 是如何工作的,那是我自己的无知。我是后端开发人员,所以很抱歉。如果它对其他人有帮助,这就是问题所在。

在vue中,子组件的onMount钩子在父组件的do之前运行

本质上,我有代码从 app.vue 中的 cookie 设置身份验证存储(我调用的主 vue )。这是在我的页面安装后调用的,因此如果用户完成刷新页面,则身份验证存储为空。

解决方案是在 app.vue 的 onBeforeMount 钩子中添加此 cookie 代码,该代码将在任何子组件 onMount 运行之前运行

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.