在 Vue2 時我們常常使用 Vuex 來做共用邏輯,組件之間的溝通,在 Vue 升級後,Vue3 官方有意將 Vuex 換成 Pinia
Pinia 相對來說沒有太多複雜的邏輯,你可以把它當成是沒有 mutations 的 Vuex,當然,在 Vue3 還是可以使用 Vuex 來操作,但 Pinia 的出現,你可以省去很多學習成本,又可以直接在 store 裡使用 composition API。
事不宜遲,來使用看看吧!
安裝 Pinia
選擇自己喜歡的方式安裝
NPM
YARN
引入 Pinia
main.js
1 2 3 4 5 6 7 8 9
| import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue'
const pinia = createPinia(); const app = createApp(App);
app.use(pinia); app.mount('#app');
|
引入後就可以來操作 Pinia 囉!
建立 stores 檔案
在 src 底下建立 stores 資料夾,裡面可以依專案需求來放置檔案
範例先使用 counter.js
1 2 3 4
| import { defineStore } from 'pinia'; export const useCounterStore = defineStore('counter', { })
|
- defineStore 第一個參數為 id,給 pinia 做 store 和 devtools 的連接
- 會以
use
來做變數開頭命名
Pinia 可以用操作起來像 Vuex 一樣的 Option Store,也可以使用 Setup Store,兩種操作起來不太一樣,以下為兩者介紹
Option Store
stores/counter.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', { state: () => { return { counter: 0 } }, getters: { doubleCount: (state) => state.counter * 2 }, actions: { addCount() { this.counter++ }, }, })
|
- Pinia 沒有 Vuex 的 mutations
- actions 要用 this 指向 state
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <script setup> import { useCounterStore } from "./stores/counter"; const store = useCounterStore(); const clickAdd = () => { store.addCount(); } </script>
<template> <h1>{{store.counter}}</h1> <button type="button" @click="clickAdd"> add </button> </template>
|
- Pinia 取出 stores 值時,不需要再寫 state、dispatch、getters,可以直接取得值
Setup Store
使用 Composition API 可以像 Vue3 使用 Component 的方式,使用 ref、reactive、computed 等等,並將要用的資料 return 出去給外面的檔案使用
stores/counter.js
1 2 3 4 5 6 7 8 9 10 11 12
| import { defineStore } from 'pinia'; import { ref, computed } from 'vue';
export const useCounterStore = defineStore('counter', () => { const counter = ref(0); const doubleCount = computed(() => counter.value * 2) function addCount() { counter.value++ }
return { counter, doubleCount, addCount } })
|
- 第二個參數為 function,裡面直接可以使用 Composition API
App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <script setup> import { useCounterStore } from "./stores/counter"; const store = useCounterStore(); const clickAdd = () => { store.addCount(); } </script>
<template> <h1>{{store.counter}}</h1> <button type="button" @click="clickAdd"> add </button> </template>
|
如此一來會跟 Options API 寫法的結果是一模一樣的,且無需處理 this 指向,與使用 Components 的 codeing style 也是一致的,寫法也更清楚簡潔
Setup Store 取 API
在 Setup Store 取 API 也是非常簡單,用 axios 取得 API 資料後,再從外部取得
stores/counter.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import { defineStore } from 'pinia'; import { ref } from 'vue'; import axios from "axios";
export const useCounterStore = defineStore('counter', () => { const name = ref('');
const fetchName = async() => { try { const res = await axios.get('https://randomuser.me/api/'); name.value = res.data.results[0].name; } catch (error) { console.log(error); } }
return { name, fetchName } })
|
App.vue
1 2 3 4 5 6 7 8 9 10 11
| <script setup> import { useCounterStore } from "./stores/counter"; const store = useCounterStore(); </script>
<template> <h1>{{ store.name.first }} {{ store.name.last }}</h1> <button type="button" @click="store.fetchName"> fetchName </button> </template>
|
Pinia 解構,storeToRefs
包裝資料
上面的範例,會看到很多都是 store 出來的,這時可以使用解構,讓程式碼簡潔一點,不過要注意的是,因 store 是用 reactive 包裝的對象,資料如果從 store 解構出來,將會破壞響應性,所以~
Pinia 的 function 可以直接從 store 解構出來,但純資料解構需使用 storeToRefs
包裝起來
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <script setup> import { storeToRefs } from "pinia"; import { useCounterStore } from "./stores/counter"; const store = useCounterStore(); const { addCount, fetchName } = store; const { name, counter } = storeToRefs(store); </script>
<template> <h1>{{counter}}</h1> <button type="button" @click="addCount"> add </button>
<h1>{{ name.first }} {{ name.last }}</h1> <button type="button" @click="fetchName"> fetchName </button> </template>
|
Store 之間的傳遞
store 之間有可能也會傳遞資料,import store 直接就可以使用,如以下範例,我們傳遞了 aboutStore 的 user 給 counterStore 做使用
store/about.js
1 2 3 4 5 6 7 8
| import { defineStore } from 'pinia'; import { ref } from 'vue';
export const useAboutStore = defineStore('about', () => { const user = ref('Lala');
return { user } })
|
stores/counter.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import { defineStore, storeToRefs } from 'pinia'; import { ref, computed } from 'vue'; import axios from "axios"; import { useAboutStore } from "./about";
export const useCounterStore = defineStore('counter', () => { const aboutStore = useAboutStore(); const { user } = storeToRefs(aboutStore);
const counter = ref(0); const doubleCount = computed(() => counter.value * 2 + user.value) function addCount() { counter.value++ }
const name = ref('');
const fetchName = async() => { try { const res = await axios.get('https://randomuser.me/api/'); name.value = res.data.results[0].name; } catch (error) { console.log(error); } }
return { counter, doubleCount, addCount, name, fetchName } })
|
REFERENCE
Vue3 + Vite 快速上手 Get Startrd EP6 - Pinia 的全域資料管理!
Pinia 官方
🚀實體工作坊分享
最近時賦學苑開了實體體驗課,即使你對程式碼沒有概念也能上手!Lala 會帶你一起做出一個個人品牌形象網站,帶你快速了解前端的開發流程,快跟我們一起玩轉 Web 吧!
🚀線上課程分享
線上課程可以加速學習的時間,省去了不少看文件的時間XD,以下是我推薦的一些課程
想學習更多關於前後端的線上課程,可以參考看看。
Hahow 有各式各樣類型的課程,而且是無限次數觀看,對學生或上班族而言,不用擔心被時間綁住
如果你是初學者,非常推薦六角學院哦!
剛開始轉職也是上了六角的課,非常的淺顯易懂,最重要的是,隨時還有線上的助教幫你解決問題!
Udemy 裡的課程非常的多,品質普遍不錯,且價格都滿實惠的,CP值很高!
也是很多工程師推薦的線上課程網站。