Search code examples
vue.jsvuejs3vue-composition-apipinia

Vue3 "Composition API", How to access a state or getter of a Pinia store, in a component's script section?


I new to Vue3 and I am building a frontend for a simple CRUD inventory API using Pinia for state management, I am trying to access some state properties in the script setup section of view pages and I get empty values. e.g I have a state called products which is an Array and is populated by fetching data from an API. When I use this state or any computed property from it in any template of a component, it works fine, but when I try to access it in a <script setup> section I get only an empty Array.

Here is the code of the store

import { ref, computed } from 'vue';
import { defineStore } from 'pinia';
import { useInitializeStore } from '@/use/useInitializeStore';
import axios from 'axios';

export const useProductStore = defineStore('products', () => {
  const products = ref([]);

  async function fetchProducts() {
    try {
      const response = await axios.get('http://localhost:5000/products');
      products.value = response.data;
    } catch (error) {
      console.log('Fetching products Failed, ', error);
    }
  }

  const { initialized, loading } = useInitializeStore(fetchProducts);

  const getProducts = computed(() => {
    return products.value;
  });


  const productsCount = computed(() => {
    return products.value.length;
  });

  function getProductById(productId) {
    return products.value.find((prod) => {
      return prod.id == productId;
    });
  }

  return {
    products,
    loading,
    initialized,
    getProducts,
    productsCount,
    getProductById,
  };

Inside the <script setup> section of a viewPage.vue, I tried to access the value of getProducts as follows:

<script setup>
import { ref, computed } from 'vue';
import { useProductStore } from '@/stores/products';

const productStore = useProductStore();

// to access getProducts I tried:
// 1)
const allProducts = computed(() => productStore.getProducts);
console.log('[products] ', allProducts);    // Proxy(Array) {}

// 2)
console.log('[products] ', productStore.getProducts);    // Proxy(Array) {}

// 3) even tried
console.log('[products] ', productStore.products);    // Proxy(Array) {}
</script>

I expect

<script setup>

// ...

// 1)
const allProducts = computed(() => productStore.getProducts);
console.log('[products] ', allProducts);    // (Array) {0: {…}, 1: {…}, 2: {…}, 3: {…}, ...}

// 2)
console.log('[products] ', productStore.getProducts);    // (Array) {0: {…}, 1: {…}, 2: {…}, 3: {…}, ...}

// 3)
console.log('[products] ', productStore.products);    // (Array) {0: {…}, 1: {…}, 2: {…}, 3: {…}, ...}
</script>

Solution

  • try storeToRefs

    import { storeToRefs } from 'pinia'
    
    const { products } = storeToRefs(productStore)
    

    then you can remove const getProducts = computed(...) form the store

    to get functions from the store you need this:

    const getProductById = (productId) => {
        return products.value.find((prod) => {
          return prod.id == productId;
        });
      }
    
      return {
        getProductById
      };
    

    usage:

    const product = productStore.getProductsById(1)
    

    PS: Use Vue Devtools to debug your app. Using console.log for reactive/computed props is not so useful