Files
home/docs/vue/pinia.md
2026-05-13 16:24:00 +08:00

4.0 KiB
Raw Blame History

状态管理

Pinia基础

安装Pinia

npm install pinia

创建Store

// stores/counter.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useCounterStore = defineStore('counter', () => {
  // state
  const count = ref(0)
  
  // getters
  const doubleCount = computed(() => count.value * 2)
  
  // actions
  function increment() {
    count.value++
  }
  
  function decrement() {
    count.value--
  }
  
  async function fetchCount() {
    // 异步操作
    const response = await fetch('/api/count')
    const data = await response.json()
    count.value = data.count
  }
  
  return { count, doubleCount, increment, decrement, fetchCount }
})

使用Store

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

const counter = useCounterStore()

// 读取state
console.log(counter.count)

// 读取getters
console.log(counter.doubleCount)

// 调用actions
counter.increment()
</script>

<template>
  <div>
    <p>Count: {{ counter.count }}</p>
    <p>Double: {{ counter.doubleCount }}</p>
    <button @click="counter.increment">+1</button>
  </div>
</template>

解构Store

storeToRefs

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

const counter = useCounterStore()

// 解构state和getters保持响应性
const { count, doubleCount } = storeToRefs(counter)

// 解构actions直接解构
const { increment, decrement } = counter
</script>

持久化

安装插件

npm install pinia-plugin-persistedstate

配置持久化

// stores/index.js
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

export default pinia

使用持久化

// stores/user.js
import { defineStore } from 'pinia'
import { ref } from 'vue'

export const useUserStore = defineStore('user', () => {
  const token = ref('')
  const userInfo = ref(null)
  
  function setToken(newToken) {
    token.value = newToken
  }
  
  function setUserInfo(info) {
    userInfo.value = info
  }
  
  function logout() {
    token.value = ''
    userInfo.value = null
  }
  
  return { token, userInfo, setToken, setUserInfo, logout }
}, {
  persist: {
    key: 'my-user-store',
    storage: localStorage,
    paths: ['token', 'userInfo']
  }
})

组合多个Store

// stores/index.js
import { useCounterStore } from './counter'
import { useUserStore } from './user'

export function useRootStore() {
  const counter = useCounterStore()
  const user = useUserStore()
  
  function resetAll() {
    counter.$reset()
    user.$reset()
  }
  
  return {
    counter,
    user,
    resetAll
  }
}

订阅状态变化

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

const counter = useCounterStore()

// 订阅state变化
counter.$subscribe((mutation, state) => {
  console.log('类型:', mutation.type)
  console.log('storeId:', mutation.storeId)
  console.log('新状态:', state)
  
  // 持久化到本地存储
  localStorage.setItem('counter', JSON.stringify(state))
})

// 订阅actions
counter.$onAction(({ name, args, after, onError }) => {
  console.log(`Action ${name} 被调用,参数:`, args)
  
  after((result) => {
    console.log(`Action ${name} 完成,结果:`, result)
  })
  
  onError((error) => {
    console.error(`Action ${name} 出错:`, error)
  })
})
</script>

插件开发

// plugins/piniaLogger.js
export function piniaLogger({ store }) {
  store.$onAction(({ name, args, after, onError }) => {
    console.log(`[${store.$id}] ${name} 开始`, args)
    
    after((result) => {
      console.log(`[${store.$id}] ${name} 完成`, result)
    })
    
    onError((error) => {
      console.error(`[${store.$id}] ${name} 失败`, error)
    })
  })
}

// 使用插件
const pinia = createPinia()
pinia.use(piniaLogger)