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

三葉Leaves
三葉Leaves Author

选项式 vs 组合式

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


1. 选项式写法 (Options Store)

这是更传统、更结构化的写法,类似于 Vue 2 的风格。你通过定义 state、getters 和 actions 这几个固定的属性来组织你的 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 就是声明普通的函数

优点:

  • 极度灵活:没有固定的 state、getters、actions 结构,你可以自由组织代码,甚至抽离可复用的逻辑到单独的 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
  • 更新于 : 2026-09-20 23:26:04
  • 链接: https://blog.oksanye.com/24429e20475b/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论