How to pass an argument to Pinia store?
Asked Answered
J

3

10

I'm making a session API call in main.js and using values from the response as the initial value for my root store. In vuex it's handled this like,

DataService.getSession()
  .then((sessionData) => {
    new Vue({
      i18n,
      router,
      // this params sessionData.session will be passed to my root store
      store: store(sessionData.session),
      render: (h) => h(App),
    }).$mount('#app');
  })

Consumed like,

export default function store(sessionData) { // here I'm getting the sessionData
  return new Vuex.Store({
    strict: process.env.NODE_ENV !== 'production',
    state: {
      // some states here
    },
  });
}

In case of Pinia we're creating a app instance & making it use like, app.use(createPinia())

And my store would be like,

// how to get that sessionData here
import { defineStore } from 'pinia'

export const useCounterStore = defineStore({
  id: 'counter',
  state: () => ({
    counter: 0
  })
})

Is it possible to pass the sessionData someway to the pinia store?

Jourdain answered 23/3, 2022 at 7:7 Comment(0)
C
26

There are 3 ways to pass parameters to a Pinia store - see the list below. You could use either #2 or #3 .

In most cases it is wise to initialise your Vue instance and show the user something while they are waiting for connections to resolve. So you may find it simpler to just access or initialise the store by calling DataService.getSession() in say a "SessionStore" action which can be async. Typically Components =access=> Stores =access=> Services.

Unlike Vuex, you don't need a root Pinia store. You can call useSomeStore() in the setup method for any component. Each store can be an island of data. Pinia stores can reference other pinia store instances. This might be particularly useful if you're migrating a set of Vuex stores to Pinia and need to preserve the old Vuex tree of stores.

1. Pass params to getter functions or actions.

export const useStore = defineStore('store1', {
  state: () => ({
    ...
  }),
  getters: {
    // return a function (curried)
    prop: (state) => (param1: string ...) => {
      // use state and param1
    }
  },
  actions: {
    action1(param1: string ... ) {
      // use 'this' as state and param1
    }    
  }
});

2. Initialise store AFTER creating it

Only works if there's one instance of this store required

export const useStepStore = defineStore('store2', {
  state: () => ({
    param1: undefined | String,
    param2: undefined | String,
    ...
  }),
  getters: {
    getStuff() { return this.param1 + this.param2; } 
  } 
  actions: {
    init(param1: string, param2: string) {
      this.param1 = param1
      this.param2 = param2
    },
    doStuff() {
      // use this.param1
    }    
  }
});

3. Use the factory pattern to dynamically create store instances

// export factory function 
export function createSomeStore(storeId: string, param1: string ...) {
  return defineStore(storeId, () => {
    // Use param1 anywhere
  })()
}

// Export store instances that can be shared between components ... 
export const useAlphaStore = createSomeStore('alpha', 'value1');
export const useBetaStore = createSomeStore('beta', 'value2');

Cockahoop answered 25/4, 2022 at 7:16 Comment(0)
V
5

You could cache the session data in your store, and initialize the store's data with that:

  1. In your store, export a function that receives the session data as an argument and returns createPinia() (a Vue plugin). Cache the session data in a module variable to be used later when defining the store.

  2. Define a store that initializes its state to the session data cached above.

  3. In main.js, pass the session data to the function created in step 1, and install the plugin with app.use().

// store.js
import { createPinia, defineStore } from 'pinia'

1️⃣
let initData = null

export const createStore = initStoreData => {
  initData = { ...initStoreData }
  return createPinia()
}

export const useUserStore = defineStore('users', {
  state: () => initData, 2️⃣
})
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import { createStore } from './store'
import * as DataService from './data-service'

DataService.getSession().then(sessionData => {
  createApp(App)
    .use(createStore(sessionData)) 3️⃣
    .mount('#app')
})

demo

Venomous answered 23/3, 2022 at 21:45 Comment(0)
P
0

When you create a store in Pinia using defineStore() you give it the initial state. So wherever you do that just pass the data into it and then do

defineStore('name', {
    state: () => {
        isAdmin: session.isAdmin,
        someConstant: 17
    },
    actions: { ... }
});
Professionalism answered 23/3, 2022 at 7:15 Comment(3)
Thanks for your reply. I get this, but my doubt is how can I make that session available to this store file. Say I've got a counter.js store. I'm making getSession call in main.js and getting some session details. How can I make that value available to this counter.js file?Jourdain
@mariappan.gameo Pinia docs show how to make a store provider that you use in each file and then you have the same store in any place you want to use it. Basically you do the defineStore() in each and the result is your storeProfessionalism
defineStore('name', { state: () => { /* here how I can make this session variable available here - if fetched in main.js */ isAdmin: session.isAdmin, someConstant: 17 }, actions: { ... } });Jourdain

© 2022 - 2024 — McMap. All rights reserved.