Home > Blockchain >  Vue 3, Pinia - getter is not filtering items
Vue 3, Pinia - getter is not filtering items

Time:07-01

I have a following code for the template:

<script setup>

import {useProductStore} from "@/store/products";
import {ref} from "vue";
import {storeToRefs} from "pinia";

const productStore = useProductStore()

let { products } = storeToRefs(productStore)
let { categories } = storeToRefs(productStore)

const { showProducts } = productStore

</script>

<template>

  <div>
    <div >
      <div >
        <button 
                @click="showProducts('all')">All</button>
        <button 
                @click="showProducts(category.id)"
                :key="category.id"
                v-for="category in categories">{{ category.name }}</button>
      </div>
      <div >
        <p v-for="product in showProducts('all')"
            :key="product.id">{{ product.name }}</p>
      </div>
    </div>
  </div>

</template>

And the code for the Pinia store:

import { defineStore } from 'pinia'
import axiosClient from '@/axios'

export const useProductStore = defineStore( 'products', {
    id : 'products',
    state: () => {
        return {
            products: [],
            categories: [],
        }
    },
    actions: {
        async getProducts()
        {

            axiosClient.get('products')
                .then((response) => {
                    const data = response.data

                    this.products = data.products
                    this.categories = data.categories
                })

        }
    },
    getters: {
        showProducts: (state) =>
        {
            return (categoryID) =>
            {
                if(categoryID === 'all')
                {
                    return state.products
                }

                return state.products.filter((product) => product.productCategoryID == categoryID)
            }
        }
    },
})

The initial data is loaded and show,but on click event is not showing filtered data (the showProducts method is fired and products are filtered, but the list is not visually changed).

What am I doing wrong here? What

CodePudding user response:

This is presumably due to the behaviour of the getter when used with arguments. The Documentation states, that using them the way you do, that the getter is no longer a getter, but a function that is simply invoked, which would suggest, that you have to invoke it after changing them again.

I'd suggest to filter the results in the component itself and map the given states.

Something along these lines:

DISCLAIMER I didn't check if the codes runs as it is written below, the code is shown to give a general idea of what I suggest.

Template:

<script setup>
import {useProductStore} from "@/store/products";
import {ref, reactive, computed} from "vue";
import {storeToRefs} from "pinia";

const productStore = useProductStore()

const state = reactive({categoryId: 'all'});

const filteredProducts = computed(() => {
   return state.categoryId === 'all' 
     ? products
     : products.filter((product) => product.productCategoryID === categoryId);
})

let { products } = storeToRefs(productStore)
let { categories } = storeToRefs(productStore)
</script>

<template>

  <div>
    <div >
      <div >
        <button 
                @click="categoryId = 'all'">All</button>
        <button 
                @click="categoryId = category.id"
                :key="category.id"
                v-for="category in categories">{{ category.name }}</button>
      </div>
      <div >
        <p v-for="product in filteredProducts"
            :key="product.id">{{ product.name }}</p>
      </div>
    </div>
  </div>
</template>

Pinia:

import { defineStore } from 'pinia'
import axiosClient from '@/axios'

export const useProductStore = defineStore( 'products', {
    id : 'products',
    state: () => {
        return {
            products: [],
            categories: [],
        }
    },
    actions: {
        async getProducts()
        {
          axiosClient.get('products')
            .then((response) => {
              const data = response.data
              this.products = data.products
              this.categories = data.categories
            })
        }
    },
})
  • Related