J4N
J4N

Reputation: 20733

How to use vue-router inside a pinia store?

I'm implementing a auth store(with firebase) and depending on the auth I want to route my user to login/logged page.

I'm basically trying to accomplish this: https://github.com/dannyconnell/vue-composition-api-course/blob/module-23/vue-composition-api-noteballs/src/stores/storeAuth.js

but in typescript.

In my main.ts, I did declare the store as property:

const app = createApp(App);
const pinia = createPinia();
pinia.use(({ store }) => {
  store.router = markRaw(router);
});
app.use(pinia);
app.use(router);
app.mount('#app');

But still, in my store, it doesn't know that I've a router property:

export const useStoreAuth = defineStore('storeAuth', {
    state: () => {
      return {
        user: {},
      } as AuthState;
    },
    actions: {
      init() {
        onAuthStateChanged(auth, user => {
          if (user && user.uid && user.email) {
            this.user = { id: user.uid, email: user.email };
            this.router.push('/'); //--> router doesn't exists
          } else {
            this.user = null;
            this.router.replace('/auth');//--> router doesn't exists
          }
        });
      },
      //...
    }
});

this.router doesn't exist, I get the following error:

Property 'router' does not exist on type '{ init(): void; registerUser(credentials: any): void; loginUser(credentials: any): void; logoutUser(): void; } & { user: { id: string; email: string; } | null; } & _StoreWithState<"storeAuth", AuthState, {}, { ...; }> & _StoreWithGetters<...> & PiniaCustomProperties<...>'.ts(2339)

So how can I make my store aware that the router property exists on the created state?

I've read this but I'm not sure what my "router" is considered, and if it's typed, how to indicate when I create the state which store type I declare?

Upvotes: 6

Views: 7409

Answers (2)

Victor Sembelidis
Victor Sembelidis

Reputation: 111

Documentation: https://pinia.vuejs.org/core-concepts/plugins.html#typing-plugins

Here is a complete example:

// main.ts
import { createApp, markRaw } from 'vue';
import { createPinia } from 'pinia';
import type { Router } from 'vue-router';
import App from './App.vue';
import router from './router';

declare module 'pinia' {
  export interface PiniaCustomProperties {
    router: Router;
  }
}

const app = createApp(App);
const pinia = createPinia();

pinia.use(({ store }) => {
  store.router = markRaw(router);
});

app.use(pinia);
app.use(router);
app.mount('#app');

Upvotes: 7

Quốc Cường
Quốc Cường

Reputation: 495

You can try this:

import { useRouter } from 'vue-router';

export const useStoreAuth = defineStore('storeAuth', {
    state: () => {
      return {
        user: {},
      } as AuthState;
    },
    actions: {
      init() {
        const router = useRouter(); //--> define router here;
        onAuthStateChanged(auth, user => {
          if (user && user.uid && user.email) {
            this.user = { id: user.uid, email: user.email };
            router.push('/'); //--> this should work
          } else {
            this.user = null;
            router.replace('/auth');//--> this should work
          }
        });
      },
    }
});

It might be a bit inconvenient to define the router in every action if you need to use it, but here's the way I'm using it, you can refer.

Upvotes: -1

Related Questions