> 專案做到這邊,有發現很多資料會需要在不同的元件中做使用,這時候就需要使用到狀態管理工具來統一管理以利使用。 > 此篇要分享的是 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']) } ```