---
# System prepended metadata

title: Vue.js ecshop 19.Pinia 狀態管理工具
tags: [ecshop 專案, "Vue.js\_"]

---

> 專案做到這邊，有發現很多資料會需要在不同的元件中做使用，這時候就需要使用到狀態管理工具來統一管理以利使用。
> 此篇要分享的是 Vue 官方推出的狀態管理工具 **Pinia**，那我們就開始吧！

### 在專案中導入 Pinia
[Pinia](https://pinia.vuejs.org/) 是一個用於 Vue.js 的狀態管理工具，它提供了一個更簡單、輕量且更易於使用的 API。
* 首先我們一樣進行套件安裝
  ```
  npm install pinia
  ```
* 接著回到 ***main.js*** 建立環境
  ```javascript
  import { createPinia } from 'pinia'

  const pinia = createPinia()

  app.use(pinia)
  ```
### 以產品資料為例
* 回到 `src` 建立一個資料夾 `stores` ，且新增一個 ***productStore.js*** 的檔案
  * 起手式會有 `state`、`getters`、`actions`，對照 option api 就是 `data`、`computed`、`methods`
  * 匯入 `pinia` 的方法 `defineStore`
  * 建立自定義的 Store `productState`
  * 要將 `getProducts()` 移過來，需要將其中會使用到的物件新增到 state
  * 並且在 actions 新增 `getProducts()` 方法內容
  ```javascript=
  import axios from 'axios'
  import { defineStore } from 'pinia'

  export default defineStore('productState', {
    state: () => {
      return {
        products: [],
        isLoading: false,
        pagination: {}

      }
    },
    actions: {
      getProducts (page = 1) {
        const api = `${process.env.VUE_APP_API}api/${process.env.VUE_APP_PATH}/products/?page=${page}`
        this.isLoading = true
        axios.get(api)
          .then((res) => {
            this.products = res.data.products
            this.pagination = res.data.pagination
            this.isLoading = false
            console.log(res.data)
          })
      }
    }
  })
  ```
* 接著回到 ***ShopProductsList.vue*** 做調整
  * 匯入 `productStore`、`mapState`、`mapActions`
  * 透過 `computed` 帶入 `state` 的內容，**原本的要刪除！**
  * 透過 `methods` 帶入 `actions` 的內容
  ```javascript=
  import PaginationCard from '@/components/PaginationCard.vue'
  import productStore from '@/stores/productStore'
  import { mapState, mapActions } from 'pinia'

  export default {
    data () {
      return {
        status: {
          loadingItem: '' // 對應品項 ID
        }
      }
    },
    components: {
      PaginationCard
    },
    inject: ['emitter'],
    computed: {
      ...mapState(productStore, ['products', 'isLoading', 'pagination'])
    },
    methods: {
      // 取得產品列表(透過 pinia)
      ...mapActions(productStore, ['getProducts']),
    }
    ...
  ```
### Loading 狀態統一管理
* 在 `src > stores` 新增 ***statusStore.js*** 檔案
* 將 `isLoading` 狀態搬移到新建立的 ***statusStore.js*** 統一管理
  ```javascript
  import { defineStore } from 'pinia'

  export default defineStore('statusState', {
    state: () => {
      return {
        isLoading: false
      }
    }
  })
  ```
* 接著在 ***productStore.js*** 要匯入 ***statusStore.js***
  ```javascript
  import statusStore from './statusStore'

  const status = statusStore()

  // 改寫成 status.isLoading
  actions: {
    getProducts (page = 1) {
      const api = `${process.env.VUE_APP_API}api/${process.env.VUE_APP_PATH}/products/?page=${page}`
      status.isLoading = true
      axios.get(api)
        .then((res) => {
          this.products = res.data.products
          this.pagination = res.data.pagination
          status.isLoading = false
          console.log(res.data)
        })
    }
  }
  ```
* 最後在 ***ShopProductsList.vue*** 匯入 ***statusStore.js***
  ```javascript
  import statusStore from '@/stores/statusStore'

  computed: {
      ...mapState(statusStore, ['isLoading'])
    },

  ```
### getters 範例
* 在 ***productStore.js*** 新增 `getters： sortProducts`
  ```javascript
  getters: {
    // 商品以價格排序
    sortProducts: (state) =>
      state.products.sort(
        (a, b) => a.price - b.price
      )
  }
  ```
* 回到 ***ProductsList.vue*** 匯入就要改成 `sortProducts`：
  ```javascript
  computed: {
    ...mapState(productStore, ['sortProducts', 'pagination'])
  }
  ```
  