如何正确安装 Pinia Store?
我正在使用 OptionsAPI 和 Pinia Store 构建 Vue 3 应用程序,但我经常遇到一个问题,提示我在调用
createPinia()
之前尝试访问商店。
我一直在遵循文档以使用 Pinia 商店外部组件,但也许我没有以正确的方式做某事。
情况如下:
我有一个登录屏幕(
/login
),其中有一个 Cognito 会话管理器,我单击一个链接,完成 Cognito 的注册过程,然后重定向到主页路由(
/
),在此路由中,我还有一个子路由,其中​​显示一个
Dashboard
组件,我在其中进行 API 调用。
在
Home
组件上,我使用
useMainStore()
调用商店,然后在我从 Cognito 重定向,然后我想在
Dashboard
内的 API 调用中使用一些状态信息。
这是我的
Home
组件,它本身运行良好,因为在
mounted()
钩子里面有
const store = useMainStore();
,我认为它在创建 Pinia 实例后总是被调用。
<template>
<div class="home">
<router-view></router-view>
</div>
</template>
<script>
import {useMainStore} from '../store/index'
export default {
name: 'Home',
components: {
},
mounted() {
const store = useMainStore();
const paramValues = {}
const payload = {
// I construct an object with the properties I need from paramValues
}
store.updateTokens(payload); // I save the values in the store
},
}
</script>
现在这是我的
Dashboard
组件:
<script>
import axios from 'axios'
import {useMainStore} from '../store/index'
const store = useMainStore();
export default {
name: "Dashboard",
data() {
return {
user_data: null,
}
},
mounted() {
axios({
url: 'myAPIUrl',
headers: { 'Authorization': `${store.token_type} ${store.access_token}`}
}).then(response => {
this.user_data = response.data;
}).catch(error => {
console.log(error);
})
},
}
</script>
上述组件将失败,并抛出一个错误,指出我在创建实例之前试图访问存储,我可以通过将存储声明移动到
mounted()
钩子内来解决这个问题,像以前一样,但是如果我想在组件内部以其他方式使用存储,而不仅仅是在
mounted
钩子中呢?而且,为什么会失败?到目前为止,由于
Home
组件已经可以访问商店,那么位于
Home
子路由内的
Dashboard
组件难道不应该已经创建了商店实例吗?
这是我的
main.js
文件,我在其中调用
createPinia()
方法。
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const pinia = createPinia();
createApp(App).use(router).use(pinia).mount('#app')
我收到的错误是:
未捕获的错误:[🍍]:调用 getActivePinia 时没有活动 Pinia。你忘记安装 pinia 了吗?
我的商店文件:
import { defineStore } from 'pinia';
export const useMainStore = defineStore('main', {
state: () => ({
access_token: sessionStorage.getItem('access_token') || '',
id_token: sessionStorage.getItem('id_token') || '',
token_type: sessionStorage.getItem('token_type') || '',
isAuthenticated: sessionStorage.getItem('isAuthenticated') || false,
userData: JSON.parse(sessionStorage.getItem('userData')) || undefined
}),
actions: {
updateTokens(payload) {
this.id_token = payload.id_token;
this.access_token = payload.access_token;
this.token_type = payload.token_type
sessionStorage.setItem('id_token', payload.id_token);
sessionStorage.setItem('access_token', payload.access_token);
sessionStorage.setItem('token_type', payload.token_type);
sessionStorage.setItem('isAuthenticated', payload.isAuthenticated);
},
setUserData(payload) {
this.userData = payload;
sessionStorage.setItem('userData', JSON.stringify(payload));
},
resetState() {
this.$reset();
}
},
})
在组件外部使用
use
组合函数是可能的,但并不常见,也不总是允许的。函数可以依赖于组件实例或特定的执行顺序,如果不遵守该顺序,则可能会发生当前问题。
必须先创建 Pinia 实例,然后才能使用它。在导入 Dashboard.vue 时会评估
const store = useMainStore()
,这始终发生在
createPinia()
之前。
对于选项 API,可以将其分配为组件实例的一部分(仅限 Vue 3):
data() {
return { store: useMainStore() }
},
或作为全局属性公开(仅限 Vue 3):
const pinia = createPinia();
const app = createApp(App).use(router).use(pinia);
app.config.globalProperties.mainStore = useMainStore();
app.mount('#app');
由于您正在使用 Vue 3,我建议您使用新的脚本设置语法:
<script setup>
import { reactive, onMounted } from 'vue'
import axios from 'axios'
import { useMainStore } from '../store'
const store = useMainStore();
const data = reactive({
user_data: null
})
onMounted (async () => {
try {
const {data: MyResponse} = await axios({
method: "YOUR METHOD",
url: 'myAPIUrl',
headers: { 'Authorization': `${store.token_type} ${store.access_token}`}
})
data.user_data = MyResponse
} catch(error){
console.log(error)
}
})
</script>
使用设置,您可以定义该存储变量并在代码中使用它。
大家经过大量研究,我找到了这个问题的答案, 你必须像下面这样传递 index.ts/js 的 const:
<script lang="ts" setup>
import store from '../stores/index';
import { useCounterStore } from '../stores/counter';
const counterStore = useCounterStore(store());
counterStore.increment();
console.log(counterStore.count);
</script>