Pinia 性能优化 #
概述 #
Pinia 本身已经非常轻量和高效,但在大型应用中,合理优化 Store 可以进一步提升性能。本节将介绍 Pinia 的性能优化技巧。
响应式优化 #
避免不必要的响应式 #
ts
// 不推荐:大型对象完全响应式
export const useDataStore = defineStore('data', {
state: () => ({
largeData: {} as Record<string, any> // 整个对象都是响应式的
})
})
// 推荐:使用 shallowRef 或 markRaw
import { shallowRef, markRaw } from 'vue'
export const useDataStore = defineStore('data', () => {
// shallowRef:只有 .value 是响应式的
const largeData = shallowRef({})
// markRaw:完全跳过响应式
const staticData = markRaw({ /* 大型静态数据 */ })
return { largeData, staticData }
})
使用 shallowRef 处理大型数据 #
ts
import { defineStore } from 'pinia'
import { shallowRef, triggerRef } from 'vue'
export const useListStore = defineStore('list', () => {
// 使用 shallowRef 避免深层响应式
const items = shallowRef<Item[]>([])
async function fetchItems() {
const response = await fetch('/api/items')
items.value = await response.json()
// 手动触发更新
triggerRef(items)
}
function updateItem(id: number, updates: Partial<Item>) {
const index = items.value.findIndex(item => item.id === id)
if (index !== -1) {
// 创建新数组触发更新
items.value = [
...items.value.slice(0, index),
{ ...items.value[index], ...updates },
...items.value.slice(index + 1)
]
}
}
return { items, fetchItems, updateItem }
})
组件订阅优化 #
精确订阅 State #
vue
<script setup>
import { storeToRefs } from 'pinia'
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
// 推荐:只订阅需要的属性
const { name, email } = storeToRefs(userStore)
// 不推荐:订阅整个 store
// const userStore = useUserStore()
// 模板中使用 userStore.user 会订阅整个对象
</script>
<template>
<!-- 推荐:精确使用 -->
<p>{{ name }}</p>
<p>{{ email }}</p>
<!-- 不推荐:访问整个对象 -->
<!-- <p>{{ userStore.user.name }}</p> -->
</template>
使用 computed 派生数据 #
vue
<script setup>
import { computed } from 'vue'
import { useProductStore } from '@/stores/product'
const productStore = useProductStore()
// 推荐:使用 computed 缓存计算结果
const expensiveValue = computed(() => {
return productStore.products.reduce((sum, p) => sum + p.price, 0)
})
// 不推荐:在模板中直接计算
// {{ productStore.products.reduce((sum, p) => sum + p.price, 0) }}
</script>
Store 设计优化 #
拆分大型 Store #
ts
// 不推荐:一个 Store 包含所有状态
export const useAppStore = defineStore('app', {
state: () => ({
user: null,
products: [],
orders: [],
cart: [],
settings: {}
})
})
// 推荐:按功能拆分
export const useUserStore = defineStore('user', { /* ... */ })
export const useProductStore = defineStore('product', { /* ... */ })
export const useOrderStore = defineStore('order', { /* ... */ })
export const useCartStore = defineStore('cart', { /* ... */ })
延迟加载 Store #
ts
// 懒加载 Store
const useAdminStore = () => {
return import('@/stores/admin').then(m => m.useAdminStore())
}
// 在需要时才加载
async function showAdminPanel() {
const adminStore = await useAdminStore()
// ...
}
按需加载数据 #
ts
export const useProductStore = defineStore('product', {
state: () => ({
products: [],
productCache: new Map<number, Product>()
}),
actions: {
async getProduct(id: number) {
// 检查缓存
if (this.productCache.has(id)) {
return this.productCache.get(id)!
}
// 从服务器获取
const response = await fetch(`/api/products/${id}`)
const product = await response.json()
// 缓存结果
this.productCache.set(id, product)
return product
}
}
})
批量更新优化 #
使用 $patch 批量更新 #
ts
// 不推荐:多次单独更新
userStore.name = 'John'
userStore.email = 'john@example.com'
userStore.age = 25
userStore.updatedAt = new Date()
// 推荐:使用 $patch 批量更新
userStore.$patch({
name: 'John',
email: 'john@example.com',
age: 25,
updatedAt: new Date()
})
// 或者使用函数形式
userStore.$patch((state) => {
state.name = 'John'
state.email = 'john@example.com'
state.age = 25
state.updatedAt = new Date()
})
防抖和节流 #
ts
import { defineStore } from 'pinia'
import { useDebounceFn, useThrottleFn } from '@vueuse/core'
export const useSearchStore = defineStore('search', {
state: () => ({
query: '',
results: []
}),
actions: {
// 防抖搜索
searchDebounced: useDebounceFn(async function(this: any, query: string) {
this.query = query
const response = await fetch(`/api/search?q=${query}`)
this.results = await response.json()
}, 300),
// 节流更新
updateResults: useThrottleFn(function(this: any, results: any[]) {
this.results = results
}, 100)
}
})
虚拟列表优化 #
分页加载 #
ts
export const useProductStore = defineStore('product', {
state: () => ({
products: [],
page: 1,
pageSize: 20,
hasMore: true,
loading: false
}),
actions: {
async loadMore() {
if (this.loading || !this.hasMore) return
this.loading = true
try {
const response = await fetch(
`/api/products?page=${this.page}&size=${this.pageSize}`
)
const data = await response.json()
this.products.push(...data.items)
this.page++
this.hasMore = data.hasMore
} finally {
this.loading = false
}
}
}
})
虚拟滚动 #
vue
<template>
<VirtualList
:items="productStore.products"
:item-size="50"
>
<template #default="{ item }">
<ProductItem :product="item" />
</template>
</VirtualList>
</template>
缓存策略 #
数据缓存 #
ts
export const useProductStore = defineStore('product', () => {
const products = ref<Product[]>([])
const lastFetchTime = ref(0)
const cacheTime = 5 * 60 * 1000 // 5 分钟缓存
async function fetchProducts(forceRefresh = false) {
const now = Date.now()
// 检查缓存是否有效
if (!forceRefresh && products.value.length > 0 && now - lastFetchTime.value < cacheTime) {
return products.value
}
const response = await fetch('/api/products')
products.value = await response.json()
lastFetchTime.value = now
return products.value
}
return { products, fetchProducts }
})
使用 Map 缓存 #
ts
export const useProductStore = defineStore('product', () => {
const productCache = ref(new Map<number, { data: Product; timestamp: number }>())
const cacheTime = 10 * 60 * 1000 // 10 分钟
async function getProduct(id: number) {
const cached = productCache.value.get(id)
const now = Date.now()
// 检查缓存
if (cached && now - cached.timestamp < cacheTime) {
return cached.data
}
// 获取新数据
const response = await fetch(`/api/products/${id}`)
const product = await response.json()
// 更新缓存
productCache.value.set(id, {
data: product,
timestamp: now
})
return product
}
return { getProduct }
})
监控和调试 #
性能监控 #
ts
// plugins/performance.ts
import type { PiniaPluginContext } from 'pinia'
export function performancePlugin({ store }: PiniaPluginContext) {
store.$onAction(({ name, after, onError }) => {
const startTime = performance.now()
after(() => {
const duration = performance.now() - startTime
if (duration > 100) {
console.warn(`Slow action: ${store.$id}.${name} took ${duration.toFixed(2)}ms`)
}
})
onError((error) => {
console.error(`Action failed: ${store.$id}.${name}`, error)
})
})
}
状态变化监控 #
ts
// 监控状态变化频率
store.$subscribe((mutation, state) => {
console.log(`State changed: ${mutation.type}`)
console.log('Changes:', mutation)
})
最佳实践总结 #
1. 精确订阅 #
ts
// 只订阅需要的状态
const { name, email } = storeToRefs(userStore)
2. 批量更新 #
ts
// 使用 $patch 批量更新
store.$patch({ /* ... */ })
3. 合理缓存 #
ts
// 缓存不常变化的数据
const cached = cache.get(key)
if (cached) return cached
4. 延迟加载 #
ts
// 按需加载 Store 和数据
const store = await import('@/stores/admin')
5. 避免深层响应式 #
ts
// 使用 shallowRef 处理大型数据
const largeData = shallowRef({})
下一步 #
现在你已经掌握了性能优化技巧,接下来让我们学习常见问题解答。
- 常见问题 - 常见问题解答
最后更新:2026-03-28