Reputation: 1228
I am using pinia and vue-router 4.x ,but i am having a problem using both of them in a store. each works independently ,but not together.
If i use
import router from '../router'
router will work but pinia is failed with error
Uncaught ReferenceError: Cannot access 'useAuthStore' before initialization
at axiosroot.ts
@line let authStore = useAuthStore(pinia);
//here is axiosroot.ts
import axios from "axios";
import {useAuthStore} from '../stores/auth-store'
import { createPinia } from "pinia";
const pinia=createPinia();
let authStore = useAuthStore(pinia);
const url = "http://127.0.0.1:8000/api";
const myToken =authStore.getToken;
export default axios.create({
url,
headers:{"Accept":"application/json"},
});
When i import router from vue-routern useRouter
is undefined
import {useRouter} from 'vue-router'
const router =useRouter();
the error
Uncaught TypeError: Cannot read properties of undefined (reading 'push')
---
error @ line router.push({name:'Login'})
// here is the remainning relavant code
import { defineStore, acceptHMRUpdate } from "pinia";
//import router from '../router'
import {useRouter} from 'vue-router'
const router =useRouter();
export const useAuthStore = defineStore({
id: "user",
actions: {
LogOut(payload) {
// this.DELETE_TOKEN(null);
// this.UPDATE_LOGIN_STATUS(false);
router.push({name:'Login'})
},
},
});
Upvotes: 29
Views: 35086
Reputation: 1
I am using quasar and resolve the error as follows.
actions: {
async login(email, password) {
.....
await this.api.post('auth/login/', data).then((response) => {
this._p.$router.push({ name: 'dashboard' });
});
},
Something you can do is console.log(this) and you will see everything that your instance contains, in my case it was in "_p". I hope and serve you.
Upvotes: 0
Reputation: 1641
Here's a pattern which seems to work quite well.
After action initState() you'll have this.route & this.router available
This is for pinia, but would work just as well with vuex.
// any store.js
export const useStore = defineStore('my-store') => {
return state: () => {
router: null,
route: null
},
actions: {
initState ({ router, route }) {
this.router = router;
this.route = route;
}
}
}
// app.vue
<script setup>
const store = useStore();
const router = useRouter();
const route = useRoute();
store.initState({ router, route })
</script>
Upvotes: 1
Reputation: 636
If you need to use router in Pinia without passing methods, props or Object a cleaner solution could be this.
import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.use(router)
app.provide('router', router);
app.mount('#app')
And then in your store:
import { inject } from "vue";
actions: {
navigate() {
const router = inject('router');
router.push({
name: "customers",
params: { page: this.currentPage },
});
},
},
pinia.use() is more flexible and allows you to pass plugins, methods, Object, props. Both are fine for the porpouse of passing router to pinia.
Upvotes: 0
Reputation: 56
For anyone using quasar v2. This worked for me
in your /src/stores/index.js file, add the following
import { markRaw } from 'vue'
import { route } from 'quasar/wrappers'
pinia.use(({ store }) => {
// important! dont add a $router here
store.router = markRaw(route)
})
Then in your src/stores/[yourStore].js file use
this.router.push("/") // important! dont add a $router here
I was having trouble when trying to add the $router as suggested in the top answer
Upvotes: 4
Reputation: 126
For anyone using quasar Framework v2
Locate /src/stores/index.js file and edit by
import { useRouter } from 'vue-router' ---> import this
// You can add Pinia plugins here
// pinia.use(SomePiniaPlugin)
pinia.router = useRouter() ---> add this line
in the Store file
this.router.push({ name: 'Home' }) --> use this
Upvotes: 2
Reputation: 205
In main.js:
import { createApp, markRaw } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const pinia = createPinia()
pinia.use(({ store }) => {
store.router = markRaw(router)
})
const app = createApp(App)
app.use(pinia)
app.use(router)
app.mount('#app')
In your store push routes with:
this.router.push({ name: 'home' });
Upvotes: 10
Reputation: 391
Router has to be used as a plugin in pinia. I read this in the pinia.documentation https://pinia.vuejs.org/core-concepts/plugins.html
When adding external properties, class instances that come from other libraries, or simply things that are not reactive, you should wrap the object with markRaw() before passing it to pinia. Here is an example adding the router to every store:
import { markRaw } from 'vue'
// adapt this based on where your router is
import { router } from './router'
pinia.use(({ store }) => {
store.router = markRaw(router)
})
This will add pinia to every store you create. The config in main.ts is the same as for vue plugins.
import { createApp, markRaw } from 'vue';
import { createPinia } from 'pinia';
import App from './app/App.vue';
import { router } from './modules/router/router';
const app = createApp(App);
const pinia = createPinia();
pinia.use(({ store }) => {
store.$router = markRaw(router)
});
app.use(router)
Now you can access router in your stores.
export const useMyStore = defineStore("myStore", {
state: () => {
return {};
},
actions: {
myAction() {
this.$router.push({ name: 'Home' });
},
});
Upvotes: 39
Reputation: 943
It should work if you declare const router = useRouter();
inside your store action instead of at the top of the module.
It's the same for const store = useSomeStore()
declarations. They can't be used at the module route, and are often used within component setup
functions and store actions.
You don't need to create a plugin, but if you're likely to be using the router across all your stores it still might be worth doing so as mentioned in this answer
Upvotes: -2
Reputation: 61
I resolved that wrapping the store in a function:
/*** THIS DOES NOT WORK ****/
const router = useRouter();
export const useLoginStore = defineStore("login", {
state: () => ({
loading: false,
error: "",
}),
actions: {
loginAction(credentials: AuthenticationRequest): Promise<void> {
await login(credentials);
router.replace("/")
},
},
});
/*** This actually works ***/
export default function useLoginStore() {
const router = useRouter();
return defineStore("login", {
state: () => ({
loading: false,
error: "",
}),
actions: {
loginAction(credentials: AuthenticationRequest): Promise<void> {
await login(credentials);
router.replace("/")
},
},
})();
}
Upvotes: 6