Vuex状态管理:之四大金刚 - 辅助函数

82 阅读1分钟

前言:

Vuex中获取数据的辅助函数有两个:mapStatemapGetters,同样的vuex也提供了mapMutationsmapActions方便操作mutationsactions方法

  1. mapState用于将state中的数据映射到组件的计算属性中
  2. mapGetters用于将getter中的计算属性映射到组件的计算属性空中
  3. 需要注意的是mapStatemapGetter是映射为计算属性,获取数据
  4. mapMutationsmapActions是映射为组件methods方法,修改数据的

1. 辅助函数说明:

  1. 之前的使用vue的方法并不是特别好.获取数据需要通过$store找到state对象,在获取数据,
  2. 操作getter,mutation,action也是如此,就会给使用带来不便
  3. vuex提供了一些辅助函数,帮助我们快速获取数据, 操作mutation,action函数

2. mapState

mapState是获取数据的辅助函数

2.1 获取数据说明
  1. 之前在使用vuex数据的时候我们都是在模板Mustache语法中直接获取数据,
  2. 这样的操作并不是特别友好,每一次都需要重新获取数据
  3. 因此比较常用的做法是将vuex中的数据获取后保存在组件的计算属性中
  4. 这样如果在组件中多次使用数据,就可以使用计算属性的缓存

之前获取数据示例代码

<div class="count">数字: {{ $store.state.count }}</div>

将数据保存在计算属性中,

示例代码如下

<template>
    <div class="home">
        <!-- 此时只需要使用计算看属性中的数据就可以了 -->
        <div class="count">数字: {{ count }}</div>
    </div>
</template>

<script>
    export default {
        name: 'Home',
        data(){

        },
        computed:{
            count(){
                return this.$store.state.count 
            }
        },
        methods:{

        }
    }
</script>
2.2 计算属性中的问题

说明:

  1. 如果在一个组件中需要使用很多vuex中的状态
  2. 那么我们就需要在组件中定义所有的需要使用数据对应的计算属性
  3. 这样反而变的繁琐

示例代码

export default {
    name: 'Home',
    data(){
        return {
            // count: 0
        }
    },
    computed:{
        count(){
            return this.$store.state.count 
        },
        user(){
            return this.$store.state.user
        },
        // ...
    },
    methods:{

    }
}
2.3 使用mapState

为了解决组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余的问题.

vuex提供了mapState辅助函数帮助我们自动生成计算属性

注意:

使用mapState有不同使用方式

2.3.1 vuex中的状态
let store = new Vuex.Store({
    state:{
        count:0,
        user:{
            name:"张三",
            age:20
        },
        fruits:[{
            name:"苹果",
            price: 22
        },{
            name:"梨子",
            price: 25
        },{
            name:"西瓜",
            price: 16
        },{
            name:"香蕉",
            price: 18
        }]
    },
    // ....

})
2.3.2 组件中计算属性名和vuex中的状态名不一致

说明:

  1. 例如组件中需要获取vuexcount数据的内容,
  2. 但是在组件中有可能也有一个名为count的数据
  3. 因此在获取vuex中的count时,组件的计算属性就不能在为count了,
  4. 故而计算属性的名和vuex状态名不一致

示例代码:

<template>
<div class="home">
    <div class="count">vuex中数据: {{ number }}</div>
    <div >组件自己的数据: {{ count }}</div>

    </div>
</template>

<script>

    // 从vuex中获取mapState
    import {mapState} from 'vuex'

    export default {
        name: 'Home',
        data(){
            return {
                count: 10
            }
        },
        computed:mapState({
            //  将vuex中状态count映射到组件计算属性number上
            // 1. 普通使用

            number: function(state){
                return state.count

                // this为当前组件实例
                // return state.count + this.count
            },

            // 2. 简写方式

            // number: state => state.count   

            // 3. 极简写法

            // 字符串"count" 等价于 state => state.count
            // number: 'count'
        }),

    }
</script>

示例说明:

  1. 计算属性的函数第一个参数为vuex中的状态state,因此可以通过state直接获取数据
  2. 计算属性值为函数, 如果只是获取vuex中数据并映射到组件就算属性上, 可以使用简写方式
  3. 如果在计算属性函数中需要使用组件自己的数据,或是有其他的逻辑操作,建议写完整函数
2.3.3 vuex状态名和计算名一样

说明:

  1. 如果vuex状态名和映射的组件计算名完全一样,
  2. mapState可以直接传字符串数组,来映射数据

实例代码:

<template>
    <div class="home">
        <div>vuex中count数据: {{ count }}</div>
        <div>vuex中user数据: {{ user }}</div>
    </div>
</template>

<script>

    import {mapState} from 'vuex'

    export default {
        name: 'Home',
        data(){
            return {
                // count: 10
            }
        },
        // 字符串数组的写法,
        // 就是将vuex中的数据count,user
        // 映射为组件计算属性count,user上
        computed:mapState([
            "count",
            "user"
        ]),
    }
</script>
2.3.4 组件有自己的计算属性

说明:

  1. 上面几个示例中,计算属性computed选项的值就是mapState
  2. 也就是组件的所有计算属性都是从stroe映射过来的
  3. 那么如果还有一个自己额外的计算属性怎么办
  4. 如果需要给组件添加自定义的计算属性,就回归到以前的写法,mapState采用解构的方式使用

示例代码

<template>
<div class="home">

    <div>vuex中数据: {{ count }}</div>
    <div>vuex中数据: {{ user }}</div>
    <div>组件计算属性值: {{ computePrice }}</div>

    </div>
</template>

<script>

    import {mapState} from 'vuex'

    export default {
        name: 'Home',
        data(){
            return {
                price: 10
            }
        },
        computed:{
            // 组件自己的计算属性
            computePrice(){
                return this.price * 2
            },
            // 通过mapState映射过来的计算属性
            ... mapState([
                "count",
                "user"
            ])
        },

    }
</script>
2.4 mapGetters的使用

说明:

  1. mapGettersvuex提供的将store中的getter映射到组件计算属性中的辅助函数
  2. mapGetters使用方式和mapState一样
  3. 最常用的方式就是解构方式

示例代码如下:

<template>
    <div class="home">
        <div>{{fruits}}</div>
        <div>{{filterFruits}}</div>
    </div>
</template>

<script>

    // 获取mapState, mapGetters 辅助函数
    import {mapState,mapGetters} from 'vuex'

    export default {
        name: 'Home',
        data(){
            return {
                price: 10
            }
        },
        computed:{
            computePrice(){
                return this.price * 2
            },
            ... mapState([
                "count",
                "user",
                "fruits"
            ]),

            // 解构mapGetters
            // 将store中getters里filterFruits
            // 映射到组件的filterFruits计算属性上
            ...mapGetters([
                "filterFruits"
            ])
        },

    }
</script>

如果store中getters里的计算属性名和组件计算属性名不同时

可以采用对象的写法

...mapGetters([
    // 组件中的计算属性名:  getters中的计算属性名
    fruits: "filterFruits"
])

3. 未使用辅助函数修改转台

3.1 设置修改状态的mutations和actions

代码如下

let store = new Vuex.Store({
    state:{
        count:0,
        user:{
            name:"张三",
            age:20
        },
        fruits:[{
            name:"苹果",
            price: 22
        },{
            name:"梨子",
            price: 25
        },{
            name:"西瓜",
            price: 16
        },{
            name:"香蕉",
            price: 18
        }]
    },
    getters:{
        filterFruits(state){
            return state.fruits.filter(fruit => fruit.price > 20)
        }
    },
    // 定义mutations
    mutations:{
        // 同步修改状态count
        increment(state, payload){
            state.count++
        }
    },
    actions:{
        // 异步修改状态count
        asyncIncrement(context){
            setTimeout(function(){
                context.commit({
                    type:"increment"
                })
            },1000)
        }
    },

})

示例说明

  1. 组件中如果通过commit触发mutation函数,就会同步更改状态count
  2. 组件中如果通过dispath异步触发action函数,
  3. action会异步触发mutation函数,通过mutation修改状态
3.2 组件中触发mutation和action
<template>
<div class="home">
    <div class="count">数字: {{ count }}</div>
    <button @click="increment">同步++</button>
    <button @click="asyncincrement">异步++</button>

    </div>
</template>

<script>
    // 获取辅助函数
    import {mapState,mapGetters} from 'vuex'

    export default {
        name: 'Home',
        data(){
            return {
                // count: 10
                price: 10
            }
        },
        computed:{
            computePrice(){
                return this.price * 2
            },
            ... mapState([
                "count",
                "user",
                "fruits"
            ]),
            ...mapGetters([
                "filterFruits"
            ])
        },
        methods:{
            increment(){
                // 同步,通过commit触发mutation函数
                this.$store.commit({
                    type:"increment"
                })

            },
            asyncincrement(){
                // 异步,通过dispatch 触发action函数
                this.$store.dispatch({
                    type:"asyncIncrement"
                })
            }
        }
    }
</script>

示例说明:

  1. increment是触发mutation同步修改状态的方法
  2. asyncIncrement是触发action异步修改状态的方法

4. 使用mapMutations

说明:

  1. 之前如果我们需要在组件中修改store的状态都需要额外定义一个方法
  2. 如果这个方法里有大量的逻辑代码还好
  3. 如果这个方法只是为了触发mutation函数,每个组件都这样定义就会比较繁琐
  4. 因此vuex提供了mapMutations辅助函数,可以将mutations函数映射为组件methods方法
4.1 方法同名

方法同名意思就是组件用来触发mutation函数的方法和mutation函数重名

就可以采用字符串数组的的方式将mutation函数通过函数名映射methods方法

数组里的字符串为mutations的函数名

代码如下:

// 通过vuex获取辅助函数
import {
    mapState,   // 获取state辅助函数
    mapGetters, // 获取getters 辅助函数
    mapMutations, // 操作mutations辅助函数
} from 'vuex'

export default {
    name: 'Home',
    data(){
        return {
            // count: 10
            price: 10
        }
    },
    computed:{
        computePrice(){
            return this.price * 2
        },
        ... mapState([
            "count",
            "user",
            "fruits"
        ]),
        ...mapGetters([
            "filterFruits"
        ])
    },
    methods:{
        ...mapMutations([
            'increment'  
            //  将this.increment 映射为 this.$store.commit("increment")
        ]),
        asyncincrement(){
            // 异步,通过dispatch 触发action函数
            this.$store.dispatch({
                type:"asyncIncrement"
            })
        }
    }
}
4.2 关于载荷

此时是将mutation函数映射为组件methods方法,

如果此时调用这个方法不传参数时, 那么将没有载荷

例如:

 <button @click="increment">同步++</button>

如果在调用这个映射方法是传递一个数据,那么这个数据将成为mutation函数的载荷

 <button @click="increment(10)">同步++</button>

一般来说,载荷会选择对象方式传递数据

 <button @click="increment({num:10})">同步++</button>
4.3 方法不同名

也就是需要映射到组件方法中的mutation函数,在组件中已经有同名的函数了

因此在映射时,就需要另外定义方法名

此时组件中被映射的方法名和mutation函数名就不同名了

此时需要选择对象的方式映射

代码如下:

// 通过vuex获取辅助函数
import {
    mapState,   // 获取state辅助函数
    mapGetters, // 获取getters 辅助函数
    mapMutations, // 操作mutations辅助函数
} from 'vuex'

export default {
    name: 'Home',
    data(){
        return {
            // count: 10
            price: 10
        }
    },
    computed:{
        computePrice(){
            return this.price * 2
        },
        ... mapState([
            "count",
            "user",
            "fruits"
        ]),
        ...mapGetters([
            "filterFruits"
        ])
    },
    methods:{
        ...mapMutations({
            // 方法名: mutation函数名
            add:'increment'  

            //  将this.add 映射为 this.$store.commit("increment")
        }),
        asyncincrement(){
            // 异步,通过dispatch 触发action函数
            this.$store.dispatch({
                type:"asyncIncrement"
            })
        }
    }
}

5. 使用mapActions

mapActions辅助函数的使用和mapMutations一样

同样也可以传递载荷

因此可以将代码修改如下

// 通过vuex获取辅助函数
import {
    mapState,   // 获取state辅助函数
    mapGetters, // 获取getters 辅助函数
    mapMutations, // 操作mutations辅助函数
    mapActions    // 操作actions辅助函数
} from 'vuex'

export default {
    name: 'Home',
    data(){
        return {
            // count: 10
            price: 10
        }
    },
    computed:{
        computePrice(){
            return this.price * 2
        },
        ... mapState([
            "count",
            "user",
            "fruits"
        ]),
        ...mapGetters([
            "filterFruits"
        ])
    },
    methods:{
        ...mapMutations({
            // 方法名: mutation函数名
            add:'increment'  

            //  将this.add 映射为 this.$store.commit("increment")
        }),
        ...mapActions([
            "asyncIncrement"

            // 将this.asyncIncrement 
            // 映射为 this.$store.dispatch("asyncIncrement")
        ])
    }
}

总结

四大辅助函数的使用

  1. mapState
  2. mapGetters
  3. mapMutations
  4. mapActions