Vue3 筆記 | Pinia 管理全域資料

更新於 發佈於 閱讀時間約 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內容數
這個專題用來存放我在學習網頁開發時的心得及知識。
留言
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
在這篇文章中,我們將討論如何在 Vue 應用中使用路由、GitHub Pages 部署以及狀態管理工具 Pinia。這些概念在開發上通常會使用到,讓我們一步一步深入這些重要的概念!
Thumbnail
狀態管理在 Vue 應用中非常重要,尤其是當多個組件需要共享狀態時。每個 Vue 組件管理自己的響應式狀態,但隨著組件數量增加,簡單的管理方式可能變得複雜。這時,可以使用如 Pinia 的狀態管理庫來簡化這一過程。Pinia 提供了一個更簡單的 API 和更強的類型推斷,並由 Vue 核心團隊維護。
Thumbnail
各位使用 Vue.js 開發的小夥伴們,你們都怎麼實作父子層組件資料的雙向綁定呢?如果你還在寫 prop + emit 的話,不妨進來看看吧。
Thumbnail
一開始你先把你的專案push上去後,修改vite.config.ts ,要在裡面新增  base: "/Cart/" (/放自己的專案名稱/) build: {outDir: "docs"}, 接下來你要去你的github setting 裡面 -> Page ->選Deploy fro
Thumbnail
VUE為單向資料流的框架,在鄰近層級之間我們可以依靠 props 由父層向子層來傳遞需要的資料,然而遇到跨層級的架構時,雖然也是可以一層層傳進去,只是這會造成多餘的處理及凌亂的程式碼,因此才有了 "provide" 來解決我們跨層級的需求。 層級展示圖
一般而言,組件之間的資料傳遞,可以使用 props 來達成,不過一旦層級過多的時候,props 就要逐層向下傳遞,會越來越麻煩且複雜。 而 provide、inject 可以解決這個問題,它可以提供一個「源頭」,子組件們可以藉由同一個源頭取得對應的資料,且沒有層級分別,都可以取得,就不用逐層傳遞資
Thumbnail
在這篇文章中,我們將討論如何在 Vue 應用中使用路由、GitHub Pages 部署以及狀態管理工具 Pinia。這些概念在開發上通常會使用到,讓我們一步一步深入這些重要的概念!
Thumbnail
狀態管理在 Vue 應用中非常重要,尤其是當多個組件需要共享狀態時。每個 Vue 組件管理自己的響應式狀態,但隨著組件數量增加,簡單的管理方式可能變得複雜。這時,可以使用如 Pinia 的狀態管理庫來簡化這一過程。Pinia 提供了一個更簡單的 API 和更強的類型推斷,並由 Vue 核心團隊維護。
Thumbnail
各位使用 Vue.js 開發的小夥伴們,你們都怎麼實作父子層組件資料的雙向綁定呢?如果你還在寫 prop + emit 的話,不妨進來看看吧。
Thumbnail
一開始你先把你的專案push上去後,修改vite.config.ts ,要在裡面新增  base: "/Cart/" (/放自己的專案名稱/) build: {outDir: "docs"}, 接下來你要去你的github setting 裡面 -> Page ->選Deploy fro
Thumbnail
VUE為單向資料流的框架,在鄰近層級之間我們可以依靠 props 由父層向子層來傳遞需要的資料,然而遇到跨層級的架構時,雖然也是可以一層層傳進去,只是這會造成多餘的處理及凌亂的程式碼,因此才有了 "provide" 來解決我們跨層級的需求。 層級展示圖
一般而言,組件之間的資料傳遞,可以使用 props 來達成,不過一旦層級過多的時候,props 就要逐層向下傳遞,會越來越麻煩且複雜。 而 provide、inject 可以解決這個問題,它可以提供一個「源頭」,子組件們可以藉由同一個源頭取得對應的資料,且沒有層級分別,都可以取得,就不用逐層傳遞資