Logo

dev-resources.site

for different kinds of informations.

Vue Tip : Setup Store Pinia + Custom Pagination

Published at
10/8/2024
Categories
vue
webdev
code
Author
Hòa Nguyễn Coder
Categories
3 categories in total
vue
open
webdev
open
code
open
Vue Tip : Setup Store Pinia + Custom Pagination

Today, I have write a example "Pagination" in Vue CLI 3 + Pinia

The first , we can install library Pinia

yarn add pinia
# or with npm
npm install pinia

Pinia help manager state in Store, we can setup state from Pinia, after then use in component

Okay, the code below, I have setup Store Product + Custom Pagination

// stores/product.ts
import { defineStore } from 'pinia'
import axios from 'axios'
export const useProductStore = defineStore('product', {
   state:()=>{
     return {
       products: [],
       perPage: 5,
       currentPage: 1,
       totalPages: 0
     }
   },
   getters: {
     all(state){
       return state.products
     },
     total(state){
       return state.totalPages
     }
   },
   actions:{
     getProducts(){
        axios.get('https://dummyjson.com/products').then((response) => {
          console.log("products",response.data.products)
          this.totalPages = response.data.products.length / this.perPage
          this.pagination(1)
        })
      },
      pagination(page : number){
       axios.get('https://dummyjson.com/products/?limit='+this.perPage+'&skip='+((page-1)*this.perPage)+
      '&select=title,thumbnail,price,rating,category').then((response) => {
         console.log("pagination",response.data.products)
         let data = response.data.products;
         this.products = data
       })
     }
   }
})

The following below code, I setup state , getters, actions. we can use it in the component

// ProductView.vue

<script>
import { computed } from 'vue'
import { useProductStore } from '../../stores/product'
export default {
  name: 'ProductView',
  setup() {
    const productStore = useProductStore()
    // Dispatch fetch products
    productStore.getProducts()
    // Reactive computed properties
    const products = computed(() => productStore.all) 
    const totalPages = computed(() => productStore.total)
    const currentPage = computed(() => productStore.currentPage)
    // Hàm thay đổi trang
    const changePage = (page) => {
      productStore.pagination(page)
      productStore.currentPage = page
    }
    return {
      products,
      totalPages,
      currentPage,
      changePage
    }
  }
}
</script>

We can call state in ProductView.vue

<template>
....
 <tbody v-if="products.length>0">
            <tr v-for="product in products" key="product.id">
              <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                <div class="flex">
                  <div class="flex-shrink-0 w-16 h-16">
                    <img
                      class="w-full h-full "
                      v-bind:src="product.thumbnail"
                      alt=""
                    />
                  </div>
                  <div class="ml-3">
                    <p class="text-gray-900 whitespace-no-wrap">
                      {{ product.title }}
                    </p>
                    <p class="text-gray-600 whitespace-no-wrap">SKU : {{ product.sku }}</p>
                  </div>
                </div>
              </td>
              <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                <p class="text-gray-900 whitespace-no-wrap">${{ product.price }}</p>
                <p class="text-gray-600 whitespace-no-wrap">USD</p>
              </td>
              <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                <p class="text-gray-900 whitespace-no-wrap">{{ product.rating }}</p>
              </td>
              <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                <span
                  class="relative inline-block px-3 py-1 font-semibold text-green-900 leading-tight"
                >
                  <span
                    aria-hidden
                    class="absolute inset-0 bg-green-200 opacity-50 rounded-full"
                  ></span>
                  <span class="relative">{{ product.category }}</span>
                </span>
              </td>
              <td
                class="px-5 py-5 border-b border-gray-200 bg-white text-sm text-right"
              >
                <button
                  type="button"
                  class="inline-block text-gray-500 hover:text-gray-700"
                >
                  <svg
                    class="inline-block h-6 w-6 fill-current"
                    viewBox="0 0 24 24"
                  >
                    <path
                      d="M12 6a2 2 0 110-4 2 2 0 010 4zm0 8a2 2 0 110-4 2 2 0 010 4zm-2 6a2 2 0 104 0 2 2 0 00-4 0z"
                    />
                  </svg>
                </button>
              </td>
            </tr>  
          </tbody>
<!-- list pagination -->
    <nav v-if="totalPages>0">
          <ul class="pagination flex flex-wrap gap-2">
            <li
              v-for="page in totalPages"
              :key="page"
              class="page-item bg-gray-500 text-white w-8 h-8 flex items-center justify-center rounded-md"
              :class="{ 'bg-green-700 text-white': currentPage === page }"
            >
              <button
                class="page-link"
                @click="changePage(page)"
              >
                {{ page }}
              </button>
            </li>
          </ul>
        </nav>
</template>

Demo:

Image description

Featured ones: