官方文档:使用 Pinia 进行状态管理 |Quasar 框架
视频教程:quasar框架store-状态管理库pinia介绍_哔哩哔哩_bilibili
使用 Quasar CLI
创建一个新的store
quasar new store date --format js
Pinia存储模板详解解
基本结构解析
import { defineStore, acceptHMRUpdate } from 'pinia'
// 定义存储
export const useMyStore = defineStore('myStore', {
state: () => ({}), // 状态定义
getters: {}, // 计算属性
actions: {} // 操作方法
})
// HMR (热模块替换)支持
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useMyStore, import.meta.hot))
}
如何扩展模板
1. 定义状态 (state)
state
是存储的核心数据部分:
state: () => ({
count: 0,
user: null,
items: [],
loading: false
})
2. 添加 getters
getters
类似于计算属性,用于派生状态:
getters: {
doubleCount: (state) => state.count * 2,
isAuthenticated: (state) => state.user !== null,
activeItems: (state) => state.items.filter(item => item.active)
}
3. 添加 actions
actions
用于修改状态和执行异步操作:
actions: {
increment() {
this.count++
},
async fetchUser(userId) {
this.loading = true
try {
const response = await api.getUser(userId)
this.user = response.data
} catch (error) {
console.error('Failed to fetch user:', error)
} finally {
this.loading = false
}
},
reset() {
this.$reset() // 内置方法,重置到初始状态
}
}
[!INFO]
Pinia也支持类似Vue3的组合式API写法
在组件中使用 Pinia Store
在 Vue 组件中使用 Pinia Store 非常简单,以下是几种常见的使用方式:
在组件 setup 中使用
<script setup>
import { useCounterStore } from '@/stores/counter'
// 在setup中获取store实例
const counterStore = useCounterStore()
// 访问状态
console.log(counterStore.count)
// 使用getter
console.log(counterStore.doubleCount)
// 调用action
function increment() {
counterStore.increment()
}
</script>
<template>
<div>
<p>Count: {{ counterStore.count }}</p>
<p>Double: {{ counterStore.doubleCount }}</p>
<button @click="increment">Increment</button>
</div>
</template>
使用 storeToRefs 解构保持响应式
<script setup>
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'
const counterStore = useCounterStore()
// 使用storeToRefs解构可以保持响应式
const { count, doubleCount } = storeToRefs(counterStore)
// actions不需要解构,可以直接从store调用
const { increment } = counterStore
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double: {{ doubleCount }}</p>
<button @click="increment">Increment</button>
</div>
</template>
选项式 API 中使用
如果你使用的是选项式 API,可以在 setup()
中使用:
<script>
import { useCounterStore } from '@/stores/counter'
export default {
setup() {
const counterStore = useCounterStore()
return { counterStore }
},
methods: {
increment() {
this.counterStore.increment()
}
}
}
</script>
<template>
<div>
<p>Count: {{ counterStore.count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
在模板中直接使用
<script setup>
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
</script>
<template>
<div>
<!-- 直接访问store属性 -->
<h1>{{ counter.count }}</h1>
<!-- 直接调用action -->
<button @click="counter.increment()">+</button>
<button @click="counter.decrement()">-</button>
<!-- 使用getter -->
<p>Double: {{ counter.doubleCount }}</p>
</div>
</template>
监听状态变化
<script setup>
import { useCounterStore } from '@/stores/counter'
import { watch } from 'vue'
const counter = useCounterStore()
// 监听count的变化
watch(
() => counter.count,
(newValue, oldValue) => {
console.log(`Count changed from ${oldValue} to ${newValue}`)
}
)
// 或者使用store的$subscribe方法
counter.$subscribe((mutation, state) => {
console.log('Store changed:', mutation, state)
})
</script>
重置 store 状态
<script setup>
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
function reset() {
counter.$reset() // 重置到初始状态
}
</script>
<template>
<button @click="reset">Reset Store</button>
</template>
最佳实践建议
- 命名一致性:store 变量命名建议使用
xxxStore
格式,如userStore
,productStore
- 避免直接修改状态:尽量通过 actions 修改状态,而不是直接赋值
- 合理使用解构:使用
storeToRefs
解构状态和 getters,但不要解构 actions - 模块化:将大型应用的状态拆分到多个 store 中
- TypeScript:如果使用 TS,可以为 store 添加类型定义以获得更好的类型支持