Search code examples
vuexvuejs3pinia

How to pass an argument to Pinia store?


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?


Solution

  • 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');