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