vuex的基本使用
创建一个store:
import {createStore} from 'vuex'
const store = createStore();
export default store;在Main.js中使用:
import store from './store'
createApp(App).use(store).mount('#app')state
在store中定义数据,需要在state属性中:
const store = createStore({
state(){
return{
counter:0
}
}
});在组件中使用时,需要从$store.state中获取:
<h2>{{$store.state.counter}}</h2>mutations
在vuex的开发模式中,不推荐直接对数据进行操作,而是应该通过commit来提交一次数据操作。在store中定义mutations属性:
mutations:{
increment(state){
state.counter++
},
decrement(state){
state.counter--
}
}在组件中调用store的commit方法,参数是要执行的mutation的方法名:
methods:{
increment(){
this.$store.commit("increment")
},
decrement(){
this.$store.commit("decrement")
}
}mutations的一些补充
mutations中的方法的第一个参数是state,可以获取state中的变量,第二个参数是payload,即从外部传入的参数:
mutations:{
incrementN(state,payload){
state.counter+=payload
}
}, methods: {
addTen(){
this.$store.commit('incrementN',10)
}
},另一种提交的风格是,将两个参数合并,即传入一个对象,当中有type来指明提交给某个函数:
this.$store.commit({
type:'incrementN',
incre:10
})另外为了防止将方法名写错,可以使用常量的方式定义方法名:
const INCREMENT_N = "increment_n";
mutations:{
[INCREMENT_N](state,payload){
state.counter+=payload
}
},mapState辅助函数
可以通过计算属性来简化获取state中的数据:
computed:{
sCounter(){
return this.$store.state.counter
}
}不过vuex为我们提供了一个函数,可以更加快速地获取到state中的变量:
import { mapState } from 'vuex'
export default {
computed:{
sCounter(){
return this.$store.state.counter
},
...mapState(["counter","name"])
}
}mapState传入的是要获取的state中的变量名数组,返回值是变量的computed对象,所以需要用…展开;也可以传入一个对象,可以自定义名字:
...mapState({
sCounter:state=>state.counter,
name:state=>state.name
})在composition API中使用
vuex提供了一个useStore方法让我们在setup中可以获取到store:
import { useStore } from 'vuex'
import { computed } from 'vue'
export default {
setup(props) {
const store = useStore();
const sCounter = computed(()=>store.state.counter)
return {
sCounter
}
}
}如果要使用mapState,需要进行一些处理:
setup(props) {
const store = useStore();
const storeStateFns = mapState(["counter","name"]);
const storeState = {};
Object.keys(storeStateFns).forEach(fnKey =>{
const fn = storeStateFns[fnKey].bind({$store:store});
console.log(fnKey);
storeState[fnKey]=computed(fn);
})
return {
...storeState
}
}mapState返回的都是函数,在执行时需要用到$store属性,所以需要加上bind。
对以上的内容进行封装以便使用:
const storeStateFns = mapState(["counter","name"]);
const storeState = {};
Object.keys(storeStateFns).forEach(fnKey =>{
const fn = storeStateFns[fnKey].bind({$store:store});
console.log(fnKey);
storeState[fnKey]=computed(fn);
})getters
一些数据可能需要结果处理之后再进行显示(和computed类似,不用在每一个组件中写计算属性),定义方式如下:
const store = createStore({
state(){},
mutations:{},
getters:{
totalPrice(state){
let totalPrice=0;
for (const book of state.books){
totalPrice+=book.count*book.price
}
return totalPrice;
}
}
});使用方式:
<h2>总价值:{{$store.getters.totalPrice}}</h2>getters中定义的函数的第一个参数是state,可以获取state中定义的变量,第二个参数是getters,可以用其调用getters中其它的函数:
getters:{
totalPrice(state,getters){
let totalPrice=0;
for (const book of state.books){
totalPrice+=book.count*book.price
}
return totalPrice * getters.currentDiscount;
},
currentDiscount(state){
return state.discount*0.9;
}
}getter函数的返回值可以是一个值,在使用时就应该如同上面所示:
<h2>总价值:{{$store.getters.totalPrice}}</h2>也可以返回一个函数,返回函数的一个目的是传入我们的自定义参数:
totalPriceForCountN(state,getters){
return function(n){
let totalPrice=0;
for (const book of state.books){
if (book.count>=n){
totalPrice+=book.count*book.price
}
}
return totalPrice * getters.currentDiscount;
}
}使用时需要在后面加上小括号表示函数调用:
<h2>总价值:{{$store.getters.totalPriceForCountN(4)}}</h2>mapGetters
使用方式和mapState类似。在computed中:
import { mapGetters } from 'vuex'
computed:{
...mapGetters(["nameInfo","counterInfo"])
},同样也有数组写法和对象写法。
在setup中使用mapGetters,也如同mapState一样需要进行一些处理:
import { computed } from 'vue'
import { mapGetters, useStore } from 'vuex'
export function useGetters(mapper){
const store = useStore();
const storeGettersFns = mapGetters(mapper);
const storeGetters = {}
Object.keys(storeGettersFns).forEach(fnKey=>{
const fn = storeGettersFns[fnKey].bind({$store: store});
storeGetters[fnKey]=computed(fn);
})
return storeGetters;
}mapMutations
在computed中使用:
import {mapMutations} from 'vuex'
export default {
methods: {
...mapMutations(["increment","decrement","increment_n"])
}
}在setup中使用:
import {mapMutations} from 'vuex'
export default {
setup(props) {
const storeMutations = mapMutations(["increment","decrement","increment_n"]);
return {
...storeMutations
}
}
}actions
action中可以进行异步的操作,处理完的结果也需要通过commit方法让mutations进行数据处理。
actions中的方法有一个context参数,它类似于store,但是在modules中可能会有所不同:
actions:{
incrementAction(context){
setTimeout(() => {
context.commit("increment")
}, 1000);
}
}第二个参数同mutations中的一样,是一个从外面传入的参数:
actions:{
incrementAction(context,payload){
console.log(payload)
setTimeout(() => {
context.commit("increment")
}, 1000);
}, methods: {
increment(){
this.$store.dispatch("incrementAction",{name:"shopkeeper"});
}
},在组件中调用actions的方式:
methods: {
increment(){
this.$store.dispatch("incrementAction");
}
},一般来说,我们会在actions编写网络请求数据的操作,以下是一个结合axios的小例子:
actions:{
getHomeUserData(context){
axios.get("http://139.155.47.131/users").then(
res=>{
context.commit("addUserData",res.data)
}
)
}
} mounted() {
this.$store.dispatch("getHomeUserData");
},context还有其它的一些属性,可以在需要的时候调用:
actions如同mutations一样有另一种派发风格,即写成一个对象:
decrement(){
this.$store.dispatch({
type:"decrementAction"
})
}mapActions
在methods中使用:
methods: {
...mapActions(["incrementAction","decrementAction"]),
...mapActions({
add:"incrementActions",
sub:"decrementActions"
})
},在setup中使用:
setup(props) {
const actions = mapActions(["incrementAction","decrementAction"])
return {
...actions
}
}actions的返回值
actions的返回值默认为undefined,实际上可以返回一个promise,以监听数据何时加载完毕:
actions:{
getHomeUserData2(context){
return new Promise((resolve,reject)=>{
axios.get("http://139.155.47.131/users").then(
res=>{
context.commit("addUserData",res.data)
resolve("success")
}
).catch(err =>{
reject(err)
})
})
},
} setup(props) {
const store = useStore();
onMounted(()=>{
const promise=store.dispatch("getHomeUserData2");
promise.then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)
})
})
}modules
基本使用:为每一个组件单独定义一个module对象,其中包含state、mutations等store中的属性。在根store中的modules属性中配置之:
const homeModule = {
state(){
return {
counter: 100
}
},
getters:{
},
mutations:{
},
actions:{
}
}
export default homeModuleimport {createStore} from 'vuex';
import home from './modules/home';
import user from './modules/user';
const store = createStore({
modules:{
home,
user
}
});
export default store;modules的命名空间
默认情况下:modules中只有state是独占的(需要使用state.xxx获取),其它的属性mutations等都是合并到根store中。此时使用getters、mutations或者actions,将会触发所有同名的变量。
如果想让module独占其内部的属性,需要加上namespaced:true:
const homeModule = {
namespaced:true,
state(){
return {
counter: 100
}
},
getters:{
doubleHomeCounter(state){
return state.counter*2;
}
},
mutations:{
increment(state){
state.counter++;
}
},
actions:{
incrementAction(context){
context.commit("increment")
}
}
}
export default homeModule需要通过类似于url的方式访问:
<template>
<div>
<hr>
<h2>当前home计数:{{$store.state.home.counter}}</h2>
<button @click="homeIncrement">home+1</button>
<h2>{{$store.getters["home/doubleHomeCounter"]}}</h2>
<button @click="homeIncrementAction">home increment action</button>
<hr>
</div>
</template>
<script>
import {useStore, mapActions} from 'vuex'
export default {
methods: {
homeIncrement(){
this.$store.commit("home/increment")
},
homeIncrementAction(){
this.$store.dispatch("home/incrementAction")
}
},
}
</script>modules的其它一些细节
module中的getters方法,除了本有的state和getters参数外,还能获取到rootState和rootGetters。
getters:{
doubleHomeCounter(state,getters,rootState,rootGetters){
return state.counter*2;
}
},module中的actions方法,其入参context对象有commit、dispatch、state、rootState、getters、rootGetters属性。
actions:{
incrementAction({commit, dispatch, state, getters, rootState, rootGetters}){
commit("increment")
}
}在commit和dispatch中,如果想要对根中的mutations操作,需要在第三个参数中增加{root: true}:
commit("increment",null,{root: true})modules中的辅助函数
如何对modules使用mapState等辅助函数,在options API中有两种写法,一种是直接通过根store来获取,那么需要一个namespace的参数;另一种是使用createNamespacedHelpers函数来对module进行操作:
import { createNamespacedHelpers} from 'vuex'
const {mapState,mapGetters,mapMutations,mapActions} = createNamespacedHelpers("home")
export default {
computed:{
//写法1:直接从根中获取
// ...mapState("home",["counter"]),
// ...mapGetters("home",["doubleHomeCounter"])
// 写法2:从home中获取
...mapState(["counter"]),
...mapGetters(["doubleHomeCounter"])
},
methods: {
// 写法1:直接从根中获取
// ...mapMutations("home",["increment"]),
// ...mapActions("home",["incrementAction"])
// 写法2:从home中获取
...mapMutations(["increment"]),
...mapActions(["incrementAction"])
},
}在composition API中: