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
有兩個參數:
- module 的名稱是唯一值,與其他 module 間不重複:user
- 對象:
- 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 簡單 範例,謝謝。