vue3 - pinia 的选项式和组合式写法

三葉Leaves Author

选项式 vs 组合式

这两种写法的核心区别与 Vue 组件的选项式 API (Options API) 和组合式 API (Composition API) 非常相似,可以直接套用这个心智模型来理解。


1. 选项式写法 (Options Store)

这是更传统、更结构化的写法,类似于 Vue 2 的风格。你通过定义 stategettersactions 这几个固定的属性来组织你的 store。

优点:

  • 结构清晰state 用来存原始数据、getters 充当了计算属性的角色、actions 用来定义各种操作 state 的方法。各司其职,一目了然。
  • 对于从 Vue 2 或 Vuex 迁移过来的开发者非常友好。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// stores/counterOptions.ts
import { defineStore } from 'pinia'

export const useCounterOptionsStore = defineStore('counterOptions', {
// 1. state: 必须是一个函数,返回初始状态对象
// Pinia 在内部会自动处理,让 state 变成响应式
state: () => ({
count: 0,
name: 'Eduardo',
}),

// 2. getters: 类似于组件的 computed 属性
getters: {
// getter 会接收 state 作为第一个参数
doubleCount(state): number {
return state.count * 2
},
// 也可以通过 this 访问 store 实例的其他属性
doubleCountAndName(): string {
return `${this.name}: ${this.doubleCount}`
}
},

// 3. actions: 类似于组件的 methods
actions: {
increment() {
// 可以通过 this 访问 state
this.count++
},
incrementBy(amount: number) {
this.count += amount
}
},
})

2. 组合式写法 (Setup Store)

这是更现代、更灵活的写法,完全拥抱 Vue 3 的组合式 API。你将在一个类似 setup() 函数的环境中定义所有内容。

一切都是那么的符合直觉: state 就是直接声明的数据,getter 用计算属性 computed 代替 ,actions 就是声明普通的函数

优点:

  • 极度灵活:没有固定的 stategettersactions 结构,你可以自由组织代码,甚至抽离可复用的逻辑到单独的 composable 函数中。
  • 类型推断更强:在复杂的场景下,TypeScript 的类型推断通常表现得更好。
  • 对于 vue3 开发者尤其友好,直接使用 computed 等特性,没有 getter 带来的认知负担。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// stores/counterSetup.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

// defineStore 的第一个参数是 store 的唯一 ID
// 第二个参数是一个类似 setup 的函数
export const useCounterSetupStore = defineStore('counterSetup', () => {
// 1. 定义 state: 使用 ref() 或 reactive()
const count = ref(0)
const name = ref('Eduardo')

// 2. 定义 getters: 使用 computed()
const doubleCount = computed(() => count.value * 2)
const doubleCountAndName = computed(() => `${name.value}: ${doubleCount.value}`)

// 3. 定义 actions: 就是普通的函数
function increment() {
count.value++
}
function incrementBy(amount: number) {
count.value += amount
}

// 4. 必须 return: 将需要暴露给外部的 state, getter, action 返回
return {
count,
name,
doubleCount,
doubleCountAndName,
increment,
incrementBy,
}
})

一些可能的问题和注意点

问题一:使用组合式写法时,state 会自动变成响应式的吗?

答:不会自动,但你需要手动让它变成响应式,而这正是组合式写法的核心。

在组合式 store 中,你必须显式地使用 Vue 的响应式 API,即 ref()reactive() 来创建你的 state,以此获得响应性。


问题二:getter 函数又该怎么写?

答:getter 就是用 computed() 函数来写的,它提供了完全相同的功能。

在组合式 store 中,你不再有 getters 这个专门的属性。取而代之,你直接使用 Vue 3 提供的 computed() 函数。

正如上面 counterSetup 示例中所示:

1
2
3
4
const count = ref(0)

// 这个 doubleCount 就是一个 getter
const doubleCount = computed(() => count.value * 2)

doubleCount 的行为和选项式写法中的 getters.doubleCount 完全一致。

总结与选择建议

特性 选项式 (Options Store) 组合式 (Setup Store)
核心 定义 state, getters, actions 对象 在一个 setup 函数中自由定义
State state() 函数返回对象,Pinia 自动处理 手动使用 ref()reactive() 创建
Getters getters 对象中定义函数 使用 computed() 函数创建
Actions actions 对象中定义函数 定义普通 function
返回 无需手动返回 必须 return 需要暴露的变量和函数
适用场景 简单 store、Vue 2 习惯、团队偏好结构化 复杂逻辑、逻辑复用、与 <script setup> 风格统一
  • 标题: vue3 - pinia 的选项式和组合式写法
  • 作者: 三葉Leaves
  • 创建于 : 2025-06-25 00:00:00
  • 更新于 : 2025-07-10 13:40:50
  • 链接: https://blog.oksanye.com/0dadab081e6a/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论