DEV Community

Cover image for Vue Tip : Setup Store Pinia + Custom Pagination
Hòa Nguyễn Coder
Hòa Nguyễn Coder

Posted on

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
Enter fullscreen mode Exit fullscreen mode

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
       })
     }
   }
})

Enter fullscreen mode Exit fullscreen mode

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>

Enter fullscreen mode Exit fullscreen mode

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>

Enter fullscreen mode Exit fullscreen mode

Demo:

Image description

Top comments (0)