关于使用Pinia时提示报错: “getActivePinia was called with no active Pinia. Did you forget to install pinia?” 的原因和解决方案
发生问题的原因
以Vue框架为例, 在
main.js
中全局注册了pinia, 在axios.js
拦截器工具类的全局作用域中使用pinia时发生错误, 提示找不到;
是因为我们在createApp(App).use(pinia).mount('#app')
之前调用了useStore()
, 调用时机不对导致的报错;
说简单点, 就是使用pinia store
时,pinia
插件还没被vue
框架初始化。
解决的办法有2种
- 使用全局单例对象, 手动集成这三者的加载时机。
- 在回调函数中使用
useStore()
, 也就是确保pinia
已经初始化成功再使用 (推荐) *
下面我先附上导致错误的代码示例, 不想浪费时间的, 可以直接跳到解决方案看代码
1. vue全局注册 pinia
main.js
import { createPinia } from 'pinia'
const pinia = createPinia()
createApp(App)
.use(pinia)
.mount('#app')
2. 定义 pinia store
store.js
import {defineStore} from "pinia";
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
getters:
{
// TODO
},
actions:
{
increment()
{
this.count++
},
decrement()
{
this.count--
},
},
})
3. 使用 pinia store
axios.js
import axios from 'axios'
import {useCounterStore} from "@/stores/nutui/store.js";
##### 报错: 重点就是这句话,放在全局作用域中了,导致被提前执行了;检查你的代码是否存在类似的情况 #####
const counterStore = useCounterStore()
// 请求拦截器
axios.interceptors.request.use( function (config)
{
// TODO 请求之前的预处理
return config;
}, function (error)
{
// TODO 请求错误时的预处理
return Promise.reject(error);
});
// 响应拦截器
axios.interceptors.response.use(function (response)
{
// 响应之前的预处理
return response.data;
}, function (error)
{
// 响应错误时的预处理
return Promise.reject(error);
});
export default axios
解决方案1 (仅参考)
使用单例模式创建
pinia
对象
1. 定义 PiniaSingleton
pinia.js
import { createPinia } from 'pinia'
// 单例模式获取 pinia对象
export const PiniaSingleton = (function ()
{
let instance;
function createInstance()
{
return createPinia();
}
return {
getInstance: function ()
{
if (!instance)
{
instance = createInstance();
}
return instance;
}
};
})();
2. vue全局注册 pinia
main.js
// 从自定义单例模式中获取pinia对象
import {PiniaSingleton} from "@/utils/pinia.js";
const pinia = PiniaSingleton.getInstance()
createApp(App)
.use(pinia)
.mount('#app')
3. 定义 pinia store
store.js
import {defineStore} from "pinia";
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
getters:
{
// TODO
},
actions:
{
increment()
{
this.count++
},
decrement()
{
this.count--
},
},
})
4. 使用 pinia store
axios.js
// 从自定义单例模式中获取 pinia对象
import {PiniaSingleton} from "@/utils/pinia.js";
const pinia = PiniaSingleton.getInstance()
const counterStore = useCounterStore(pinia)
// 请求拦截器
axios.interceptors.request.use( function (config)
{
// TODO 请求之前的预处理
return config;
}, function (error)
{
// TODO 请求错误时的预处理
return Promise.reject(error);
});
// 响应拦截器
axios.interceptors.response.use(function (response)
{
// 响应之前的预处理
return response.data;
}, function (error)
{
// 响应错误时的预处理
return Promise.reject(error);
});
export default axios
5. 这样就可以在axios.js
这个外部文件中正常使用pinia store
了
在
useStore(xx)
时, 参数中指定pinia
全局单例对象即可PS: 因为
useStore(xx)
是在全局作用域中使用的, 此时vue-pinia
插件环境还没加载出来, 所以需要我们手动设置
解决方案2 (推荐)
准确说, 这不叫解决方案。我们在axios的回调函数中使用pinia就不会报错, 因为axios的回调肯定是在项目初始化完毕才会触发的, 这样就不会出现调用时机不对而导致的错误!
1. vue全局注册 pinia
main.js
import { createPinia } from 'pinia'
const pinia = createPinia()
createApp(App)
.use(pinia)
.mount('#app')
2. 定义 pinia store
store.js
import {defineStore} from "pinia";
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
getters:
{
},
actions:
{
increment()
{
this.count++
},
decrement()
{
this.count--
},
},
})
3. 使用 pinia store
axios.js
import axios from 'axios'
import {useCounterStore} from "@/stores/nutui/store.js";
// 请求拦截器
axios.interceptors.request.use( function (config)
{
return config;
}, function (error)
{
return Promise.reject(error);
});
// 响应拦截器
axios.interceptors.response.use(function (response)
{
##### 在回调函数中,是可以正常使用useStore()的,因为这个时候,pinia已经初始化完毕了 #####
const counterStore = useCounterStore()
return response.data;
}, function (error)
{
return Promise.reject(error);
});
export default axios