定义Store

vuex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* store/vuexStore.js
*/
import { createStore } from 'vuex'

// 创建一个新的 store 实例
export const vuexStore = createStore({
// ...
})

/**
* main.js
*/
import { vuexStore } from "./store/vuexStore"
app.use(vuexStore)

pinia

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* store/counter.js
*/
import { defineStore } from 'pinia'

// id: 'counter'
export const useCounterStore = defineStore('counter', {
// ...
})

/**
* main.js
*/
import { createPinia } from 'pinia'
app.use(createPinia())

State

vuex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* store/vuexStore.js
*/
export const vuexStore = createStore({
state () {
return {
count: 0
}
}
})

/**
* views/home.vue
*/
import { useStore } from 'vuex'
const store = useStore()

<p>{{ store.state.count }}</p>

pinia

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
/**
* store/piniaStore.js
*/
export const useCounterStore = defineStore('counter', {
state: () => {
return {
count: 0,
msg: 'hello'
}
},
actions: {
async setCount(ctx) {
const count = await getCount()
this.count = count
}
}
})

/**
* views/home.vue
*/
import { useCounterStore } from '../store/piniaStore.js';
const store = useCounterStore()

<p>{{ store.count }}</p>

pinia 支持响应式的 解构 state,同时也可以解构出 actions

1
2
3
4
5
6
7
8
import { storeToRefs } from 'pinia'
const store = useCounterStore()

// 解构 state, 并使其保持响应式
const { count, msg } = storeToRefs(store)

// 解构 actions
const { setCount } = store

Getters

vuex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* store/vuexStore.js
*/
export const vuexStore = createStore({
state() {
return {
count: 0
}
},
getters: {
doubleCount(state) {
return state.count * 2
}
}
})

/**
* views/home.vue
*/
<p>{{ store.getters.doubleCount }}</p>

pinia

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* store/piniaStore.js
*/
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
increment() {
this.count++
},
},
})

/**
* views/home.vue
*/
<p>{{ store.doubleCount }}</p>

Actions

vuex 中,我们会使用分发 action 的方式来触发 mutation ,以达到修改状态的目的,并且会在 action 中完成异步操作(比如接口请求等),等到异步数据后通过调用 mutation 的方式进行后续操作。

pinia 移除了 mutation 操作,我们可以在 action 一次性完成对所有操作,API更加简洁,少了一步操作。

vuex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export const vuexStore = createStore({
state() {
return {
count: 0
}
},
mutations: {
setCount(state, value) {
state.count = value
},
},
actions: {
async setCount(ctx) {
const count = await getCount()
ctx.commit("setCount", count)
}
}
})

pinia

1
2
3
4
5
6
7
8
9
10
11
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
actions: {
async setCount(ctx) {
const count = await getCount()
this.count = count
}
}
})

另外,pinia 还支持直接(批量)修改 state

1
2
3
4
5
6
7
8
9
10
11
import { useCounterStore } from '../store/piniaStore.js'
const store = useCounterStore()

// 直接修改state
store.count = 2

// 还可以批量修改state
store.$patch({
count: 2022,
msg: "aha",
});

Modules

vuex

vuex 通过定义不同的 module ,然后组合起来使用,通过 namespace 来区分模块:

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// 定义
import { createStore } from 'vuex'

const moduleA = {
namespace: 'moduleA',
state() {
return {
count: 2022
}
},
mutations: {
setCount(state, value) {
state.count = value
}
}
}

const moduleB = {
namespace: 'moduleB',
state() {
return {
msg: 'hello'
}
},
mutations: {
setMsg(state, value) {
state.msg = value
}
}
}

export default createStore({
strict: true,
state() {
return {
name: 'yushare'
}
},
modules: {
moduleA,
moduleB
}
})

// 使用
import { useStore } from 'vuex'
const store = useStore()

console.log(store.state.moduleA.count) // 2022
store.commit('setCount', 10086)

console.log(store.state.moduleA.msg) // 'hello'
store.commit('setMsg', 'aha.')

pinia

pinia 使用 id 来区分模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 定义
import { defineStore } from 'pinia'

export const useStoreA = defineStore({
id: 'useStoreA',
state: () => {/* ... */}
})

export const useStoreB = defineStore({
id: 'useStoreB',
state: () => {/* ... */}
})

// 使用
import { useStoreA } from '../store/useStoreA.js'
import { useStoreB } from '../store/useStoreB.js'
const storeA = useStoreA()
const storeB = useStoreB()

typescript支持

vuex

vuex 默认并没有提供对 ts 的完整支持,声明文件需要自己编写,官方提供了相应的文档 TypeScript 支持

pinia

pinia 官方提供了很好的 ts 支持。

总结

  1. pinia 中没有 module 的概念,保持了不同 store 之间的独立性;
  2. pinia 中移除了 mutation,API更简洁;
  3. pinia 拥有完整的 typescript 支持;
  4. pinia 支持使用插件扩展;
  5. 。。。。。。

🌰