Search code examples
vue.jsvuejs3pinia

Pinia store: Initial data fetching on store creation


In my Vue app I am using several Pinia stores. For most of them, I need to initialize the state with data from a server, i.e. I need to wait for a server response. I'm trying to do this with Setup style stores.

I don't want to explicity call an initialize function somewhere else in the code. So currently, if I access the state, the store checks if it is initialized and then - if necessary - gets the data from the server.

This looks something like this:

myStore.js

import { defineStore } from "pinia";
import { ref, computed } from "vue";
import myApi from "server";


export const myStore = defineStore("myStore", () => {
  const data = ref();
  const isInitialized = ref(false);

  // Get data from server and set state to initialized. Only get data if the store is not yet initialized.
  async function fetchData() {
    if (!isInitialized.value) {
      const res = await myApi.fetchData();
      data.value = res.data;
      isInitialized.value = true;
    }
  }

  // Getter for accessing data. First fetch data from server if necessary.
  const getData = computed(() => {
    fetchData();
    return data;
  });

  return { getData };
});

Now this isn't nice, since computed should be side-effect free and I don't want to repeat this for all the other getters in this store.

Is there something similar like lifecycle hooks for Pinia stores? Then I could simply directly get the data, as soon as the store is created. If this isn't possible, what would be a better pattern to achieve the same result?


Solution

  • Store initialization is synchronous, not to mention that there would be race conditions when uninitialized data is accessed without a promise to await.

    There needs to be explicit initialization method:

    async function initialize() {
      await myApi.fetchData();
    }
    

    Which should be called as early as needed, e.g. in root component with suspense, or with top-level await:

    await myStore.initialize()
    

    Another case for initialization method is that store initialization can be parametrized, this makes the usage more flexible and improves testability.