Skip to content

Pinia

Pinia 可以儲存網頁的狀態,讓元件間的資料共享更方便

安裝

輸入指令安裝,或是建立專案時選擇

bash
npm i pinia

設定

main.js 引用

js
import { createPinia } from 'pinia'
createApp()
  .use(createPinia())
  .mount()

建立

建立一個資料名稱為 ID 的檔案,若名稱為 user,則建立 src/store/user.js
語法分為 Options 和 Composition 兩種

js
import { defineStore } from 'pinia'
// 定義一個 ID 為 user 的 store
export const useUserStore = defineStore('user', {
  // 狀態資料,使用箭頭函式定義,類似 data
  state: () => {
    return {
      name: '',
      email: '',
      age: 0
    }
  },
  // 修改狀態用的 function
  actions: {
    setAge (value) {
      this.age = value
    }
  },
  // 可以先將資料處理好用傳出,類似 computed
  getters: {
    // 單純處理
    isAdult () {
      return this.age >= 18
    }
  }
})
js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
// 定義一個 ID 為 user 的 store
export const useUserStore = defineStore('user', () => {
  // state 狀態,使用 ref、reactive 定義
  const name = ref('')
  const email = ref('')
  const age = ref(0)

  // actions 修改狀態用一般的 function
  const setAge = (value) => {
    age.value = value
  }

  // getters 用 computed 定義
  const isAdult = computed(() => age.value >= 18)

  // 回傳要讓外部使用的資料和方法
  return { name, email, age, setAge, isAdult }
})

使用

在元件內使用時要注意,解構狀態會失去響應性,需要搭配 storeToRefs 使用

html
<script setup>
import { storeToRefs } from 'pinia'
import { useUserStore } from './store/user'
const user = useUserStore()

// 直接存取 store、getter 值
console.log(user.name, user.email, user.isAdult())

// 解構 state 需要搭配 storeToRefs,否則資料修改時不會動態更新
const { name, email, age, isAdult, isOlderThan } = storeToRefs(user)
// 解構 action 直接解構即可,預先定義好的 function 不會改變
const { setAge } = user

// 使用 $patch 修改 store 資料
user.$patch(state => {
  state.age++
})

// 直接改也可以
user.name = 100
name = 100

// 呼叫 action 修改
user.setAge(100)
setAge(100)
</script>

元件外使用

js
import { useUserStore } from './store/user'

router.beforeEach((to) => {
  const user = useUserStore()
  if (to.meta.login && !user.isLoggedIn) return '/login'
})

持久化

Pinia 本身沒有提供持久化功能,可以使用套件 pinia-plugin-persistedstate 將狀態保存至 LocalStorage

bash
npm i pinia-plugin-persistedstate
js
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
js
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => {
    return {
      name: '',
      age: 0
    }
  },
  persist: {
    // localStorage 資料名稱
    key: 'user',
    // 只存 name
    pick: ['name'],
  },
})

export const useUserStore = defineStore('user', 
  () => {
    const name = ref('')
    const age = ref(0)
    return { name }
  },
  {
    persist: {
      key: 'user',
      pick: ['name'],
    },
  }
)