Vue3 筆記 | Pinia 管理全域資料

更新於 2024/11/06閱讀時間約 9 分鐘

Vue 的狀態 (資料) 是靠著 ref reactive 儲存,然後靠著 propsemit 在組件中傳遞,可是如果今天專案一大,難免會有需要資料共享的狀況,那時不免要 propsprops 去、emitemit 去。

針對這個問題,當然也可以選擇使用 Provide-Inject 的方式來傳遞,但其實有更好的做法,就是用 Pinia 統一管理資料。



Pinia 使用

在 Vue 專案建立的時候其實就有選項問說要不要使用 Pinia 來做管理,如果選了的話,當專案建立完會在 /src 下發現一個 stores 資料夾,同時在 main.js 中也會發現 Pinia 自動被引入:

import './assets/main.css'

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const app = createApp(App)

app.use(createPinia())

app.mount('#app')


如果是舊專案要引入 Pinia,也可以透過 npm install pinia 的方式下載安裝,在自己手動修改 main.js 的內容。



認識 store

新專案會在 /src/stores 下預設建立好一個 counter.js 作為範例,它就是一個 store。

Store 負責儲存可供全域使用的狀態及邏輯,換句話說,它可以儲存 data、computed 以及 method。

定義一個 store,必須先從 pinia 引入 defineStore,命名的時候通常以 "use 開頭 + 這個 store 主要幹的事 + store 結尾"defineStore 接受兩個參數,一個是 store id,大可直接放入去掉 use 的命名;第二個是一個 arrow function,裡面就是儲存資料或邏輯的地方。

現在來看一下 pinia 預先在專案裡給我們的例子:

import { ref, computed } from 'vue'
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}

return { count, doubleCount, increment }
})

會發現 store 裡的資料或邏輯寫法跟在 <script setup> 裡寫的基本一樣,這是組合式的寫法,較早一點的選項式寫法更簡便易懂。然後透過 return 把資料或邏輯給拋出來給全域使用。



引用 store 內部資料或邏輯

在組件中我們可以直接 import 要用的 store,並把內容除存在某變數之中 (xxStore 之類的),之後可以在組件中調用 xxStore 內部的資料或邏輯。

App.vue:

<script setup>
import {useCounterStore} from '@/stores/counter'

const store = useCounterStore()
</script>

<template>
<h1>{{ store.count }}</h1>
<button @click="store.increment">Add</button>
</template>

我們可以看到畫面渲染出 store 中定義的 count 並且按鈕也可以運作。



Store 的解構

Store 的解構一句你想解構的是資料還是方法有不同做法。如果單純是方法可以直接解構,但如果是響應式資料 (包括 computed) 則要使用 storeToRefs 來做提取,看一下官方的例子,來實做看看:

App.vue:

<script setup>
import { storeToRefs } from 'pinia'
import {useCounterStore} from '@/stores/counter'

const store = useCounterStore()
const {count, doubleCount} = storeToRefs(store)
const {increment} = store

</script>

<template>
<h1>{{ count }}</h1>
<button @click="increment">Add</button>
</template>

畫面一樣可以運作,解構成功!



Store 狀態的重置

我們可以在 store 中定義 $reset 方法來讓狀態重置:

Counter.js:

// 添加 reset 方法
const $reset = () => count.value = 0

return { count, doubleCount, increment, $reset }

App.vue:

<script setup>
import {useCounterStore} from '@/stores/counter'

const store = useCounterStore()
</script>

<template>
<h1>{{ store.count }}</h1>
<button @click="store.increment">Add</button>
<button @click="store.$reset">Reset to 0</button>
</template>

當我們點擊重置按鈕時,畫面數字就會歸零了。



數據修改

存在 store 中的數據有三種修改方式:

  1. 直接修改,但不推薦:
<button @click="store.count++">Add</button>
  1. 引用方法:
<button @click="store.increment">Add</button>
  1. 使用 $patch
const addCount = () =>{
store.$patch(state =>{
state.count++
})
}

<button @click="addCount">Add</button>



數據監聽

可不可以用 watch?當然可以,但 pinia 提供了屬於它的 $subscribe 用法。

Subscribe 接收兩個參數,一個是 mutation,一個是監聽對象。Mutation console.log 出來又有三個數性值:

  1. type:記錄數據變化是通過什麼途徑。
  2. storeId:就當前 store 的 id。
  3. events:state 改變的具體數據。

我們在 App.vue 中新增一個 subscribe

store.$subscribe((mutation, state) =>{
console.log('Something changed!')
})

當我們點擊按鈕後會 console.logSomething changed!

raw-image

我們也可以用 watch 做監聽,但記得添加深層監聽:

watch(store, state =>{
console.log(`watch here`, state)
}, {deep : true})



Action (方法) 的監聽

如同監聽數據一般,Vue 可以用 $onAction 監聽方法的使用,比方說我要監聽 increment 這個函式的執行時間:

store.$onAction(({ name, after }) => {
if (name === 'increment') {
const startTime = Date.now();

after(() => {
console.log(
`Finished "${name}" after ${
Date.now() - startTime
}ms.`
);
});
}
})

打開 devtool 就可以看到監測到的執行時間。

raw-image



參考資料

  1. Pinia 官方文件
  2. Vue3 + Vite 快速上手 Get Startrd EP6 - Pinia 的全域資料管理!
avatar-img
18會員
37內容數
這個專題用來存放我在學習網頁開發時的心得及知識。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Jeremy Ho的沙龍 的其他內容
Vue3 學習筆記,元件與資料傳遞篇
Vue3 學習筆記,專案建立與基礎響應式篇
AWS 佈署簡單操作以及 RDS 建立篇
AWS 部署學習 - Day1,註冊與安裝 EB
記錄一下 API 串接的四種方式 www
Vue3 學習筆記,元件與資料傳遞篇
Vue3 學習筆記,專案建立與基礎響應式篇
AWS 佈署簡單操作以及 RDS 建立篇
AWS 部署學習 - Day1,註冊與安裝 EB
記錄一下 API 串接的四種方式 www
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
在 Vue 應用中直接使用 .reverse() 來修改陣列可能在開發環境中未出現問題,但在生產環境中卻可能導致重新渲染錯誤及資料順序不一致的問題。建議使用 .slice() 創建淺拷貝的解決方案,以確保 Vue 的反應性系統能正常運作並避免應用當機。
Thumbnail
一開始你先把你的專案push上去後,修改vite.config.ts ,要在裡面新增  base: "/Cart/" (/放自己的專案名稱/) build: {outDir: "docs"}, 接下來你要去你的github setting 裡面 -> Page ->選Deploy fro
Thumbnail
前言 Vue 是一個現代開發框架,擁有完尚的生態系,讓我們可以將須多元件客製化,做出組件,並且可重複利用,高擴充性。在開發組件時,每個組件都擁有自己的生命周期,Vue 組件會偵測每個變數值,是否有變,並且更新內容,今天要一個一個了解 Vue 的生命週期,讓大家有更多認識。 Vue 的生命週期
父元件 傳遞方法使用@ <template>    ...    <Login @modalClose="modalClose"/> ... </template> <script setup>     const _modal = ref();     function m
父元件 傳遞變數時須加上冒號 子元件 接收props用法如下 本筆記參考: 1. https://www.netlify.com/blog/understanding-defineprops-and-defineemits-in-vue-3.2 2. https://juejin.cn/post/7
Thumbnail
雖然距離上次Vue直播班課不到一年,但看到這次的課程有Pinia內容,手又不小心刷了魔法小卡(? 意識到自己的成長應該是可以輕鬆地串接API,畢竟去年也已經串到可以去烤串店了XD,就算是重新複習,還是可以從中獲得新的成長,而且發現到老師一年講的比一年還好,今年有很多觀念講得更清楚了! 可惜這次第六週
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
在 Vue 應用中直接使用 .reverse() 來修改陣列可能在開發環境中未出現問題,但在生產環境中卻可能導致重新渲染錯誤及資料順序不一致的問題。建議使用 .slice() 創建淺拷貝的解決方案,以確保 Vue 的反應性系統能正常運作並避免應用當機。
Thumbnail
一開始你先把你的專案push上去後,修改vite.config.ts ,要在裡面新增  base: "/Cart/" (/放自己的專案名稱/) build: {outDir: "docs"}, 接下來你要去你的github setting 裡面 -> Page ->選Deploy fro
Thumbnail
前言 Vue 是一個現代開發框架,擁有完尚的生態系,讓我們可以將須多元件客製化,做出組件,並且可重複利用,高擴充性。在開發組件時,每個組件都擁有自己的生命周期,Vue 組件會偵測每個變數值,是否有變,並且更新內容,今天要一個一個了解 Vue 的生命週期,讓大家有更多認識。 Vue 的生命週期
父元件 傳遞方法使用@ <template>    ...    <Login @modalClose="modalClose"/> ... </template> <script setup>     const _modal = ref();     function m
父元件 傳遞變數時須加上冒號 子元件 接收props用法如下 本筆記參考: 1. https://www.netlify.com/blog/understanding-defineprops-and-defineemits-in-vue-3.2 2. https://juejin.cn/post/7
Thumbnail
雖然距離上次Vue直播班課不到一年,但看到這次的課程有Pinia內容,手又不小心刷了魔法小卡(? 意識到自己的成長應該是可以輕鬆地串接API,畢竟去年也已經串到可以去烤串店了XD,就算是重新複習,還是可以從中獲得新的成長,而且發現到老師一年講的比一年還好,今年有很多觀念講得更清楚了! 可惜這次第六週