我遇到一个问题,如果我尝试通过
null
钩子访问它,我的 Pinia 商店将包含其每个状态属性的 onMounted
。实际情况比这稍微复杂一些。这是基本上的调用堆栈
组件
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);
}
})
想通了。当然,如果不知道 Nuxt3/Vue3 是如何工作的,那是我自己的无知。我是后端开发人员,所以很抱歉。如果它对其他人有帮助,这就是问题所在。
在vue中,子组件的onMount钩子在父组件的do之前运行
本质上,我有代码从 app.vue 中的 cookie 设置身份验证存储(我调用的主 vue )。这是在我的页面安装后调用的,因此如果用户完成刷新页面,则身份验证存储为空。
解决方案是在 app.vue 的 onBeforeMount 钩子中添加此 cookie 代码,该代码将在任何子组件 onMount 运行之前运行