夜猫小说无广告版
32.18MB · 2025-11-14
大家好,欢迎来到第11期的 JavaScript 库推荐!本期为大家介绍的是 Pinia——Vue 官方推荐的状态管理库。它以组合式 API 为核心,兼具直观、类型安全、轻量与可扩展的特点,能高效解决多组件共享状态、复杂业务流转与工程化可观测性不足的痛点,适合中大型 Vue 3 项目与 Nuxt 3 应用。
本文将从 Pinia 的核心特性、安装使用、实际应用、最佳实践与进阶用法等维度展开,帮助你系统掌握该库的使用方法。
@pinia/nuxt)。pnpm add pinia
import { createApp } from 'vue'
import { createPinia, defineStore } from 'pinia'
import { ref, computed } from 'vue'
import App from './App.vue'
// 创建并注册 Pinia
const app = createApp(App)
const pinia = createPinia()
app.use(pinia)
// Setup 风格 Store(推荐)
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubled = computed(() => count.value * 2)
const increment = () => { count.value += 1 }
const reset = () => { count.value = 0 }
return { count, doubled, increment, reset }
})
app.mount('#app')
/**
* 选择性持久化插件:仅持久化指定字段
* @param {{ store: any, options: Record<string, any> }} ctx - 插件上下文
* @returns {void}
*/
const persistSelectivePlugin = ({ store, options }) => {
const cfg = options?.persist
if (!cfg) return
const key = `pinia:${store.$id}`
const pick = (obj, paths) => paths.reduce((acc, k) => (acc[k] = obj[k], acc), {})
const cached = localStorage.getItem(key)
if (cached) store.$patch(JSON.parse(cached))
store.$subscribe((_m, state) => {
const data = Array.isArray(cfg.paths) ? pick(state, cfg.paths) : state
localStorage.setItem(key, JSON.stringify(data))
}, { detached: true })
}
import { createPinia } from 'pinia'
const pinia = createPinia()
pinia.use(persistSelectivePlugin)
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useAuthStore = defineStore('auth', () => {
const token = ref('')
const roles = ref([])
const isAuthed = computed(() => token.value !== '')
const login = async () => { token.value = 'mock-token'; roles.value = ['user'] }
const logout = () => { token.value = ''; roles.value = [] }
return { token, roles, isAuthed, login, logout }
})
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useCartStore = defineStore('cart', () => {
const items = ref([])
const total = computed(() => items.value.reduce((s, i) => s + i.price * i.qty, 0))
const add = (p) => { items.value.push({ ...p, qty: 1 }) }
const remove = (id) => { items.value = items.value.filter(i => i.id !== id) }
const clear = () => { items.value = [] }
return { items, total, add, remove, clear }
})
this,建议改用 Setup 风格或外部纯函数。// 精准订阅:storeToRefs 保持解构后的响应式
import { storeToRefs } from 'pinia'
const { count, doubled } = storeToRefs(useCounterStore())
// 批量更新:使用函数式 $patch,避免多次变更
const patchFn = (store) => { store.$patch((s) => { s.count += 2 }) }
// 解耦订阅:detached 避免组件销毁自动取消
const subscribeChanges = (store) => {
store.$subscribe((_m, state) => console.log('state:', state), { detached: true })
}
// 使用 $onAction 记录完成与错误,辅助定位
const watchActions = (store) => {
store.$onAction(({ name, after, onError }) => {
const t = performance.now()
after(() => console.log(`${name} done`, Math.round(performance.now() - t), 'ms'))
onError((e) => console.error(`${name} error`, e))
})
}
// 路由切换或组件卸载时重置临时状态
const resetState = (store) => { store.$reset?.() /* Setup 风格自定义 reset */ }
// 持久化仅保留必要字段,避免写入大对象或隐私数据
this:改用 Setup 风格或外部函数。storeToRefs。// 插件:动作日志
const actionLoggerPlugin = ({ store }) => {
store.$onAction(({ name, after, onError }) => {
const start = performance.now()
after(() => console.log(`[action] ${name}`, Math.round(performance.now() - start), 'ms'))
onError((err) => console.error(`[action] ${name} error:`, err))
})
}
// SSR:序列化 pinia.state.value 并在客户端回填
// HMR:acceptHMRUpdate(useXxxStore, import.meta.hot)
Pinia 以直观、类型安全与可扩展著称,是管理 Vue 3 复杂状态的首选方案。建议优先使用 Setup 风格编写 Store,搭配 storeToRefs 精准订阅与插件机制实现持久化与可观测性;对大型应用按领域拆分 Store,并为关键动作做好命名与日志。