[Vue 學習筆記] 快速上手 Pinia

Shino Liu
6 min readMay 30, 2022

--

Pinia基本介紹

why pinia?

  • 支持 option API / composition API
  • 沒有 Mutations,只有 state、getters、actions
  • 沒有 nested modules,只有 stores ( 每個 store 間互相獨立 )
  • 支持 TypeScript
  • 支持 SSR
  • 支持 Vue DevTools

Pinia vs Vuex

基本安裝

yarn add pinia
# 或者使用 npm
npm install pinia

vue3

// main.js
import { createPinia } from 'pinia'
app.use(createPinia())

vue2

import { createPinia, PiniaVuePlugin } from 'pinia'Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
el: '#app',

// ...
pinia,
})

在 stores 目錄下建立一個 store

import { defineStore } from 'pinia'
export const userStore = defineStore('user', {
state: () => ({
count: 0,
arr: []
}),
// 或是 return 寫法
state: () => {
return {
count: 0,
arr: []
}
},
getters: { ... },
actions: { ... }
})

defineStore 有兩個參數:

  1. module 的名稱是唯一值,與其他 module 間不重複:user
  2. 對象:
  • states:儲存全域變數,必須是箭頭函式 (相當於 vue data)
  • getters:封裝計算屬性,有緩存功能 (相當於 vue computed)
  • actions:用來定義商業邏輯,修改 state (相當於 vue methods)

在元件中使用 State

// EX: 訪問 state 裡的屬性 count
<template>
<div>{{ user_store.count }}</div>
</template>
<script setup>
import { userStore } from '../store'
const user_store = userStore()
// 使用解構
// const { count } = userStore()
</script>

上述使用解構並沒有保有響應式,如要保持響應式需使用方法storeToRef() :

// EX: 訪問 state 裡的屬性 count
<template>
<div>{{ count }}</div>
</template>
<script setup>
import { storeToRefs } from 'pinia'
import { userStore } from '../store'
const user_store = userStore()// 使用解構
// const { count } = storeToRef(userStore)
</script>

原因是因為 Pinia 把 state 都做了 reactive 處理,和 Vue3 的 reactive 同理,解構出來不是響應式,因此需要 ref 做響應式。

Getters

  • 具有緩存功能
  • 等同 state 的計算值 ( 相當於 computed ),計算之後回傳值
  • 如在頁面中多次使用,第一次會調用 getters,如數據沒改變情況下則會讀取緩存
export const useStore = defineStore('main', {
state: () => ({
counter: 0,
}),
getters: {
// 自動將返回類型推斷為數字
doubleCount: (state) => state.counter * 2
// 定義返回類型 ( TypeScipt中 )
// 不傳參數,使用 this
doublePlusOne(): number {
return this.counter * 2 + 1
}
},
})

NOTE:傳參數 state 調用 state 中的變數,不傳參數使用 this 調用。

元件中調用:

<template>
<p>count is {{ store.counter }}</p>
<p>Double count is {{ store.doubleCount }}</p>
</template>
<script>
export default {
setup() {
const store = useStore()
return { store }
},
}
</script>

訪問同個 store 其他 getter

export const useStore = defineStore('main', {
state: () => ({
counter: 0,
}),
getters: {
doubleCount: (state) => state.counter * 2,
// 使用 this
doubleCountPlusOne() {
return this.doubleCount + 1
},
},
})

訪問不同 store 其他 getter

import { useOtherStore } from './other-store'export const useStore = defineStore('main', {
state: () => ({
localData: ...
}),
getters: {
otherGetter(state) {
const otherStore = useOtherStore()
return state.localData + otherStore.data
},
},
})

Actions

  • 等同於 methods
  • 可以透過 this 調用 state,以及 action 間互相調用
  • 可以使用非同步
  • 在元件中載入後可以直接調用 Actions 內的方法
import { defineStore } from 'pinia'export const useCounterStore =  defineStore('counter', {
state: () => {
return {
count: 0
}
},
actions: {
increment() {
this.count++
}
}
})

在元件中:

import { useCounterStore } from '@/stores/counter'export default {
setup() {
const counter = useCounterStore()
counter.count++
// or using an action instead
counter.increment()
},
}

最後附上 Codesandbox 簡單 範例,謝謝。

--

--

Shino Liu
Shino Liu

No responses yet