最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - I can't access my routes from the store Pinia Vuejs3 - Stack Overflow

programmeradmin3浏览0评论

I can't access my routes from the store. There may be a good explanation for this. I use Vuejs3 and Pinia

My store :

import {defineStore} from 'pinia'
import {useRoute} from "vue-router";


type navigationState = {
    selectedNavigationItem: INavigationItem | null,
    selectedNavigationPage: INavigationPage | null,
}

export const useNavigationStore = defineStore('navigationStore', {
    state: () => ({
        /**
         * when the user clicks on an element of the navbar we store the navigation item here
         */
        selectedNavigationItem: null,
        /**
         * when the user clicks on an element of the sidebar we store the navigation page here
         */
        selectedNavigationPage: null,
    } as navigationState),
    actions: {

        /**
         * Set Selected navigation page
         * @param navigationPage
         * @type INavigationPage
         */
        setSelectedNavigationPage(navigationPage: INavigationPage | null) {
            console.log(useRoute())
            this.selectedNavigationPage = navigationPage
        },
    },
})

when I do a console log like in the method setSelectedNavigationPage

I have an undefined

I can't access my routes from the store. There may be a good explanation for this. I use Vuejs3 and Pinia

My store :

import {defineStore} from 'pinia'
import {useRoute} from "vue-router";


type navigationState = {
    selectedNavigationItem: INavigationItem | null,
    selectedNavigationPage: INavigationPage | null,
}

export const useNavigationStore = defineStore('navigationStore', {
    state: () => ({
        /**
         * when the user clicks on an element of the navbar we store the navigation item here
         */
        selectedNavigationItem: null,
        /**
         * when the user clicks on an element of the sidebar we store the navigation page here
         */
        selectedNavigationPage: null,
    } as navigationState),
    actions: {

        /**
         * Set Selected navigation page
         * @param navigationPage
         * @type INavigationPage
         */
        setSelectedNavigationPage(navigationPage: INavigationPage | null) {
            console.log(useRoute())
            this.selectedNavigationPage = navigationPage
        },
    },
})

when I do a console log like in the method setSelectedNavigationPage

I have an undefined

Share Improve this question edited Feb 27, 2022 at 9:46 Roland 27.8k9 gold badges106 silver badges103 bronze badges asked Feb 24, 2022 at 9:11 MysterdevMysterdev 2593 silver badges9 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 7

EDIT: Thanks for sophiews for pointing this out.

Just found out that we have different way to defineStore: Setup Stores

// src/stores/user.js

import { defineStore } from 'pinia'
import { useRoute, useRouter } from 'vue-router'
import api from './api.js'

export const useUserStore = defineStore('User', () => { // use function
  const route = useRoute()
  const router = useRouter()
  
  const login = async () => {
    await api.POST('login', {username, password})
    router.replace({name: 'home'})
  }

  return { login } // IMPORTANT: need to return anything we need to expose
})

Old answer

You can add router as Pinia plugin

// src/main.js
import { createPinia } from 'pinia'
import { createApp, markRaw } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import App from './App.vue'
import Home from './views/HomePage.vue'
import Api from './api.js' // my axios wrapper

const app = createApp(App)

// I usually put this in a separate file src/router.js and export the router
const routes = [ 
  { path: '/', ponent: HomePage },
]
const router = createRouter({
  history: createWebHistory(),
  routes,
})

const pinia = createPinia()
pinia.use(({ store }) => {
  store.router = markRaw(router)
  store.api = markRaw(Api)
})

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

Then router and api are available on this

// src/stores/user.js

import { defineStore } from 'pinia'

export const useUserStore = defineStore('User', {
  state: () => ({}),
  actions: {
    async login() {
      await this.api.POST('login', {username, password})
      this.router.replace({name: 'home'})
    }
  }
})

Note that you can't call this.router with arrow function.

login: async () => {
  this.router.replace({name: 'home'}) // error
}

For typescript user, to correctly get type for this.router and this.api:

// src/global.d.ts
import { Router } from 'vue-router'
import Api from './api'

export { }

declare global {

}

declare module 'pinia' {
  export interface PiniaCustomProperties {
    router: Router,
    api: typeof Api
  }
}

I found this way on pinia github. https://github./vuejs/pinia/discussions/1092

But I still don't know how to add this.route to Pinia.

Future reader, please ment if you know how to do it.

useRoute and useRouter must be used in Vue ponents and specifically setup method or inside script setup.

useRouter Docs

useRoute Docs


If you want to access the router though, you can simply import it:

router-file

import { createRouter, createWebHistory } from 'vue-router'

export const router = createRouter({
  history: createWebHistory(),
  routes: [/* ... */]
})

then in your pinia store you can import and use the router from that file:

import { defineStore } from 'pinia'
import router from './router'

export const myStore = defineStore('myStore', () => {
  // router.push
  // router.replace
})

You could wrap the process of instantiating a store within a factory/function, this will allow you to expand the stores capabilities regarding your custom needs. Below you can see that we can instantiate a store referencing the urql client and the router object. Have a look:

    export class StoreManager {
  static _instances: any[] = [];
  public static spawnInstance(
    id: string,
    storeType?: EStoreType,
    clientHandle?: ClientHandle,
    routerHandle?: Router,
  ) {

    if (StoreManager._instances.find((i) => i.id === id)) {
      const store = StoreManager._instances.find((i) => i.id === id).instance;
      return store;
    } else {
      const store = StoreManager.initStore(
        id,
        storeType,
        clientHandle ?? null,
        routerHandle ?? null,
      );
      StoreManager._instances.push({
        id: id,
        instance: store,
        storeType: storeType,
      });
      return store;
    }
  }

  public static initStore(
    id: string,
    storeType: EStoreType,
    clientHandle: ClientHandle | null,
    routerHandle: Router | null,
  ) {
    const baseState = {
      _meta: {        
        storeType: storeType,
        isLoading: true,        
      },
      _client: clientHandle,
      _router: routerHandle,
    };

    const baseActions = {
      async query(query: any, variables: any[] = []) {
        // use urql client
        
      },
    };
    const baseGetters = {
      storeType: (state) => state._meta.storeType,
      getCurrentRoute: (state) => {
        if (!state._router) {
          throw new RouterNotSetException(
            `This store does not have a router set up`,
          );
        }
        return state._router.currentRoute.fullPath.replace('/', '');
      },
    };

    switch (storeType) {
      case EStoreType.DEFAULT:
        return defineStore({
          id: `${id}`,
          state: () => ({
            ...baseState,
          }),
          actions: {
            ...baseActions,
          },
          getters: {
            ...baseGetters,
          },
        });

      default:
        throw new StoreTypeNotFoundException(
          `Expected valid 'EStoreType', got ${storeType}`,
        );
    }
  }
}

Within your VueComponent a store instance would be spawned like this:

const store = StoreManager.spawnInstance(
  uuidv4(),
  EStoreType.DEFAULT,
  useClientHandle(),
  useRouter(),
)();

Answering how to access the route in your pinia store if it's in Option Store syntax since it wasn't really answered and @ChristhoferNatalius specifically asked for an answer.

It seems like you can add the route as a plugin to the pinia store in much the same way you would add the router as a plugin.

// main.js
import { useRoute } from 'vue-router'

const pinia = createPinia();
pinia.use(({ store }) => {
  store.route = useRoute();
})

app.use(pinia);

// inside your Options Store...
const store = defineStore('myStore', {
  state: () => ({ ... })
  actions: {
    mapUrlQueryParamsToFilters() {
      console.log('route', this.route); // entire route object is here
    }
  }
})

I'm not sure if it's fully correct but i seem to be able to access the route object just fine... I created a thread on Pinia's Github Discussion so people can tell me if i'm wrong lol...

https://github./vuejs/pinia/discussions/2732

发布评论

评论列表(0)

  1. 暂无评论