Vue3 使用 vuex

项目结构

在 store 文件夹下新建 user.js 和 cart.js 作为子模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const static = () => ({

})

const getters = {

}

const mutations = {

}

const actions = {

}

export default {
namespaced: true,
state,
getters,
mutations,
actions
}

然后在 index.js 中引入:

1
2
3
4
5
6
7
8
9
10
import { createStore } from 'vuex'
import user from './modules/user'
import cart from "./modules/cart";

export default createStore({
modules: {
user,
cart
}
})

在组件中使用

state

state 保存着全局的状态,这些状态是具有响应性的,应放在 computed 属性中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import {useStore, mapState} from 'vuex';
import {computed} from "vue";

setup() {
const store = useStore();

// 不使用辅助函数
const username = computed(() => store.state.user.username);
const age = computed(() => store.state.user.age);

// 使用辅助函数
const stateFns = mapState('user', ['username', 'age']);
const State = {};
Object.keys(stateFns).forEach(fn_key => {
const fn = stateFns[fn_key].bind({$store:store});
State[fn_key] = computed(fn);
});

return {
username,
age,
...State
}
}

这里使用 bind({$store:store}) 是因为我们需要将通过 useStore 初始化的 store 与全局 $store 绑定,才可以访问到仓库中的内容。


getters

getters 的作用是对 state 中的数据进行一系列的计算,然后将结果返回。

getters 中的属性也应放在 computed 中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import {useStore, mapGetters} from 'vuex';
import {computed} from "vue";

setup() {
const store = useStore();

// 不使用辅助函数
const username = computed(() => store.getters['user/getUsername']);
const age = computed(() => store.getters['user/getAge']);

// 使用辅助函数
const getterFns = mapGetters('user', ['getUsername', 'getAge']);
const Getter = {};
Object.keys(getterFns).forEach(fn_key => {
const fn = getterFns[fn_key].bind({$store:store});
Getter[fn_key] = computed(fn);
});

return {
username,
age,
...Getter
}
}

mutations

mutations 的作用是更改 state 的属性值,但是它必须是 同步的。

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
import {useStore, mapMutations} from 'vuex';

setup() {
const store = useStore();

// 不使用辅助函数
function changeState() {
store.commit('user/changeName', 'Bob');
store.commit('user/changeAge', 22);
}

// 使用辅助函数
const mutationFns = mapMutations(['changeAge', "changeName"]);
const Mutation = {};
Object.keys(mutationFns).forEach(fn_key => {
Mutation[fn_key] = mutationFns[fn_key].bind({$store:store});
});
const {changeName, changeAge} = Mutation;

function changeState() {
changeName('Bob');
changeAge(23);
}

return {
changeState
}
}

actions

可以在 actions 中提交 mutations,actions 支持异步。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import {useStore, mapActions} from 'vuex';

setup() {
const store = useStore();

// 不使用辅助函数
function changeState() {
store.dispatch('user/changeNameAsync', 'xxx');
store.dispatch('user/changeAgeAsync', 'xxx');
}

// 使用辅助函数
const actionFns = mapActions('user', ['changeNameAsync', 'changeAgeAsync']);
const Actions = {}
Object.keys(actionFns).forEach(fn_key => {
Actions[fn_key] = actionFns[fn_key].bind({$store:store});
});

const {changeNameAsync, changeAgeAsync} = Actions;

function changeState() {
changeNameAsync('xxx');
changeAgeAsync(23);
}

为什么 state 必须放在计算属性中?

如果我们将 state 中的属性放在 data 中:

1
2
3
4
5
data() {
return {
username: this.$store.state.username
}
}

由于 data 只在 created 之前初始化一次,那么当通过提交 mutations 的方式修改 state 中的数据后,data 不会再次执行 this.$store.state.username,因此 username 的值也不会改变。

那为什么放在 computed 中就可以响应呢?因为 computed 属性通过依赖计算求值。

1
2
3
4
5
computed: {
name() {
return this.$store.state.username;
}
}

也就是说,name 依赖于 this.$store.state.username,那么当 state 中的 username 发生改变后,computed 会重新获取它的值。