开发者问题收集

如何正确安装 Pinia Store?

2022-02-17
7755

我正在使用 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();
    }
  },
})
3个回答

在组件外部使用 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');
Estus Flask
2022-02-17

由于您正在使用 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>

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

thidzz
2022-02-17

大家经过大量研究,我找到了这个问题的答案, 你必须像下面这样传递 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>
Pirooz Jenabi
2022-11-04