如何正确安装 Pinia Store?

How to properly install a Pinia Store?

我正在使用 OptionsAPI 和 Pinia Store 构建一个 Vue 3 应用程序,但我经常 运行 遇到一个问题,指出我试图在 createPinia() 被调用。

我一直在按照文档使用 Pinia 存储外部组件,但也许我没有以正确的方式做某事。

情况如下:

我有一个登录屏幕 (/login),其中有一个 Cognito 会话管理器,我单击 link,完成 Cognito 的注册过程,然后被重定向到主路由 (/),在这条路线中,我还有一个子路线,显示了一个 Dashboard 组件,我在其中进行了 API 调用。

Home 组件上,我使用 useMainStore() 调用商店,然后在从 Cognito 重定向后使用 URL 上的信息更新状态,然后我想要在 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 组件已经可以访问商店,那么 Dashboard 组件是否应该在 Home 内的子路由内已经创建了商店实例?

这是我的 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')

我得到的错误是:

Uncaught Error: []: getActivePinia was called with no active Pinia. Did you forget to install 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();
    }
  },
})

由于您使用的是 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>

使用设置,您可以定义该存储变量并通过您的代码使用它。

在组件外部使用 use 组合函数是可能的,但并不常见,而且并不总是被允许的。函数可以依赖于组件实例或特定的执行顺序,如果不遵守,就会发生当前问题。

需要创建Pinia实例才能使用。 const store = useMainStore() 在导入 Dashboard.vue 时计算,这总是发生在 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');