Home > OS >  Do I need to import Pinia store props multiple times in a Vue component?
Do I need to import Pinia store props multiple times in a Vue component?

Time:03-29

I am working on my first Vue project. I'm used to React and vanilla js, but just getting my head around a few concepts in Vue here.

In particular, importing state and action props from a Pinia store, and seemingly having to import those multiple times in a single Vue component (something I don't need to do in React).

In this example, I am importing a simple count value, and an increment function, and trying to use these in a few different places:

<script setup>
// I import everything initially in setup, which works fine,
// and these props (currentCount and incrementCount)
// can be used in my template:
import { storeToRefs } from 'pinia';
import { useStore } from '@/stores/store';
const { currentCount } = storeToRefs(useStore());
const { incrementCount } = useStore();
</script>

<template>
  <main>
    Current count: {{ currentCount }}
    <button @click="incrementCount">Increment</button>
  </main>
</template>

<script>
// I can't use store values from setup here.
// This doesn't work:
// console.log(currentCount);

// I also can't import store values here.
// I get the following error:
// "getActivePinia was called with no active Pinia"
// const { currentCount } = storeToRefs(useStore());

export default {
  mounted() {
    // I have to import store values here for them to work:
    const { currentCount } = storeToRefs(useStore());
    console.log(currentCount);
  },
  watch: {
    // weirdly, this reference to watching "currentCount" works:
    currentCount() {
      // I also have to import store values here for them to work:
      const { currentCount } = storeToRefs(useStore());
      console.log(currentCount);
    },
  },
};
</script>

As you can see, if I want to use store values in my template, on mount, and in a watcher (whereby I'd use React's useEffect hook) I am having to import the store props 3 times in total.

Is this correct / normal? Is there a simpler way to achieve what I'm doing, where I only import props once? I want to be sure I haven't missed something and am not doing something in an unusual way.

Thanks for any help and advice!

CodePudding user response:

Pinia was designed with Composition API in mind. Which implies instead of the Options API mounted, watch, data, etc... you move everything in setup function and you use onMounted and watch imported directly from vue (or from @vue/composition-api if you're still on Vue2):

in your case:

import { defineComponent, onMounted, watch, toRefs } from '@vue/composition-api'; 
                                               // or from 'vue' in Vue3
export default defineComponent({
  setup() {
    const store = useStore();

    onMounted(() => {
      console.log(store.currentCount);
    });

    watch(
      () => store.currentBrightness,
      (newVal, oldVal) => {
        console.log('currentBrightness', { newVal, oldVal })
      }
    );

    return {
      ...toRefs(myStore)
    }
  }
})

If you use Options API, you'd need to call useStore() inside each of the methods, computed or life-cycle hooks where you need to use it.


Alternatively, in Options API you could use the mapState helper from Pinia and then you could use this.currentBrightness or this.currentCount directly.

e.g:

import { mapState } from 'pinia'
// ...

  computed: {
    ...mapState(useStore, ['currentBrightness', 'currentCount'])
  }
// you can now use `this.currentBrightness` in any hook/method/computed

CodePudding user response:

If you want to combine pinia stores with the options API, one way to do it is to use the setup() function inside the options to call useStore:

<script>
import { useStore } from '@/stores/store';

export default {
  setup() { 
    const store = useStore();
    return {store}
  },
  watch: {
    store.currentBrightness(newVal, oldVal){
      // your code
    }
  },
  methods: {
   // inside methods use this.store
  },
  mounted() {
    console.log(this.store.currentCount);
  }
}
</script>

Some might consider this as a unwanted mix of composition and options API, but in my view it is a quite good solution for pinia stores.

  • Related