Files
home/docs/vue/pinia.md
2026-02-21 15:39:27 +08:00

225 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 状态管理
## Pinia基础
### 安装Pinia
```bash
npm install pinia
```
### 创建Store
```javascript
// 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
```vue
<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
```vue
<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>
```
## 持久化
### 安装插件
```bash
npm install pinia-plugin-persistedstate
```
### 配置持久化
```javascript
// stores/index.js
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
export default pinia
```
### 使用持久化
```javascript
// 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
```javascript
// 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
}
}
```
## 订阅状态变化
```vue
<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>
```
## 插件开发
```javascript
// 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)
```