vue3+ts vuex的使用
1、state
state写法有变化,新版state的写法和vue2的data写法神似,是一个函数返回一个对象,而不是一个普通的对象了。由于是用ts写的,所以创建的state一定要有类型。
import { createStore } from "vuex";
//一定要有类型
interface States {
count: number;
}
// 创建一个新的 store 实例
const store = createStore<States>({
state() {
return {
count: 0,
};
},
});
export default store;
1.1 在组件中使用
在组件里面要使用vuex里面的state数据,首页组件导入store文件,然后store.state.xxx(数据名)就可以获取数据了。
import store from "@/store";
onMounted(() => {
console.log(store.state.count);
});
2、mutations
mutations同样是用来改变state里面的数据,而且是同步的操作,必须使用mutations来更改state里面的数据。mutations里面的函数第一个参数接收一个state,这样就能更改state里的数据了。第二个参数也叫载荷,也就是使用的时候可以传入额外的参数,如果有多个,可以传入一个对象。
import { createStore } from "vuex";
//一定要有类型
interface States {
count: number;
}
// 创建一个新的 store 实例
const store = createStore<States>({
state() {
return {
count: 0,
};
},
mutations:{
increment(state:any,value:number):void{
state.count+=value;
}
}
});
export default store;
2.1 在组件中使用
在组件中使用mutations来更改state里面的数据,一定要使用commit来提交一个申请,使用格式:store.commit("定义好的函数名",传入的参数)。注意mutations只能执行同步的操作,异步的操作执行不了!!!
import store from "@/store";
onMounted(() => {
//括号里面的名称对应的是想触发的mutations里面函数的名称,后面是参数,这样就会触发store里面的mutations的increment函数。
store.commit("increment",1)
});
3、actions
和以前一样,actions负责异步的更改state数据,但是它不能直接更改,而是提交一个mutations,触发mutations来更改state的数据。Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 来获取 state。第二个参数同样是一个载荷,也就是额外的参数。
import { createStore } from "vuex";
//一定要有类型
interface States {
count: number;
}
// 创建一个新的 store 实例
const store = createStore<States>({
state() {
return {
count: 0,
};
},
mutations:{
increment(state:any,value:number):void{
state.count+=value;
}
}
actions:{
//这个名字可以随便起,和上面一样也没关系。函数里面进行了commit mutations,提交了mutations里面的increment,触发了increment这个函数,把
额外的参数传进去,mutations里面的increment负责更改state的count。
incrementAction(context:any,value:number){
context.commit("increment",value)
}
}
//官网给出一种解构的写法,因为context和store一样有相同的方法和属性,所以也有commit,把commit解构出来 {commit} 就变成了官网的那种写法
});
export default store;
3.1 在组件中使用
注意因为actions里面的必须是异步操作,所以在使用的时候也必须是异步的才能使用,比如点击按钮,让state的count加1,用dispatch触发actions
<template>
<div class="home">
<el-button type="primary" round @click="onSubmit">Primary</el-button>
</div>
</template>
import store from "@/store";
const onSubmit = () => {
store.dispatch("incrementAction", 1);
};
4、getters
有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数:如果有多个组件需要用到此属性,我们要么复制这个函数,或者 抽取到一个共享函数然后在多处导入它——无论哪种方式都不是很理想。Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。
import { createStore } from "vuex";
//一定要有类型
interface States {
count: number;
todo:any[];
}
// 创建一个新的 store 实例
const store = createStore<States>({
state() {
return {
count: 0,
todo:[{age:2},{age:3},{age:4}]
};
},
getters:{
getArray:(state:any)=>{
return state.todo.filter((item:any)=>item.age>=3);
}
}
});
export default store;
4.1 组件中的使用
直接store.state.getArray就可以得到过滤后的数据了
5、modules
如果store中的内容过多我们可以按照功能模块分成多个modules,每一个都有和大store有相同的state、mutations等数据。如果不开启命名空间,小模块和大的store有相同的函数名,那么在别的组件调用的时候,相同函数名的都会调用,调用的方法和以前一样。如果功能很复杂数据很多的话建议开启命名空间。
5.1、namespaced
一定要注意,是namespaced,最后面是d,之前一直丢了d这个字母,一直报错type找不到,找了好久原因!!!
实现有个user的模块,以下的代码结构:
store下面index文件是大的模块,modules文件夹下面是小的模块,state文件夹放的是模块state的类型。
store下面的index.ts:
import { createStore } from "vuex";
import OtherType from "./states/index";
import user from "./modules/user";
interface CommonState {
name: string;
age: number;
count: number;
}
type states = CommonState & OtherType;
// 创建一个新的 store 实例
const store = createStore<states>({
state() {
return {
count: 0,
name: "张三",
age: 10,
};
},
mutations: {
increment(state) {
state.count++;
},
},
actions: {
increment({ commit }: any, value: number) {
commit("increment", value);
},
},
modules: {
user,
},
});
export default store;
modules下的user.ts:
import UserState from "../states/userType";
const user = {
namespaced: true,
state: (): UserState => ({
name1: "李四",
age: 10,
todo: [{ age: 1 }, { age: 3 }, { age: 4 }],
}),
mutations: {
changeName(state: any, value: string): void {
state.name1 = value;
console.log(state.name1);
},
},
actions: {
changeName({ commit }: any, value: string): void {
commit("changeName", value);
},
},
getters: {
getArray: (state: any) => {
return state.todo.filter((itme: any) => itme.age >= 3);
},
},
};
export default user;
state下的userType.ts:
interface TodoType {
age: number;
}
export default interface UserState {
name1: string;
age: number;
todo?: TodoType[];
aa?: boolean;
}
index.ts:
import UserState from "./userType";
export default interface OtherType {
user?: UserState;
}
子模块开启命名空间之后,使用子模块的方法,只需要在方法前面加上模块名字就行。我上面的模块名称是user,如果使用changeName这个函数,就是store.commit("user/changeName",'123') store.dispatch("user/changeName",'123')。访问子模块state中的数据,store.state.user.name1
还有很多子模块和主模块的参数,详情见官网。
6、组合式API
可以通过调用 useStore 函数,来在 setup 钩子函数中访问 store。
<script lang="ts" setup>
import { useStore } from 'vuex'
const store = useStore()
</script>
为了访问 state 和 getter,需要创建 computed 引用以保留响应性,这与在选项式 API 中创建计算属性等效。
要使用 mutation 和 action 时,只需要在 setup 钩子函数中调用 commit 和 dispatch 函数。
7、InjectionKey
正常使用useStore的时候,取出来的数据是any的类型,如果想要取出的数据是带类型的,可以用InjectionKey,具体使用方法见官网,vuex篇章useStore 组合式函数类型声明。但是如果使用我在上面的方法直接导入store.index文件,这样的话是带类型的 import store from '../store/index'