一文学会使用Vuex

Vuex的使用

什么是Vuex,这里就不介绍了,请移步到官网 vuex.vuejs.org/zh/guide/ 学习,这里咱们只须要知道Vuex能够用来作应用的状态管理。 首先来看一下使用vue create my-project命令生成项目的时候,自动生成的Vuex的代码,store.js:vue

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {

  },
  mutations: {

  },
  actions: {

  }
})

复制代码

下面咱们来搞懂模版代码中的state,mutations,actions是干吗的,既然Vuex能够用来作状态管理,那么管理的是什么?咱们知道vue是mvvm架构,想到mvvm 咱们就是想到数据驱动ui,因此,状态管理,说白了管理的就是数据,那么咱们就能够把咱们须要操控的数据放在state里面vuex

state

状态,也就是存放咱们须要操控的数据数组

mutations

改变,若是咱们须要改变state中的数据的时候能够在这里面操做,怎么操做?下面说bash

actions

行为,和mutations相似,咱们想要改变state中的数据的时候能够在这里面进行操做,一样,怎么操做,下面说架构

既然是状态管理,若是咱们直接操做state去改变他的值的话,固然就称不上管理,Vuex采用集中式存储管理应用的全部组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化 ,固然不会直接让咱们去修改state里面的值。若是想要改变状态的值怎么办,mutations登场:异步

store.js:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
    state: {
        userInfo: {}
    },
    mutations: {
        setUserInfo(state) {
            let info = {
                name: 'wfq',
                age: 26
            }
            state.userInfo = info
        }
    },
    actions: {}
})
复制代码

而后在咱们的页面上,咱们能够这样使用:mvvm

<template>
    <div>
        <div>name:{{$store.state.userInfo.name}}</div>
        <el-button type="primary" size="small" @click="$store.commit('setUserInfo')">获取用户信息</el-button>
    </div>
</template>

<script>
    export default {
        name: "vuex1",
        data() {
            return {}
        },
        methods: {},
        mounted() {
        }
    }
</script>

<style scoped>

</style>
复制代码

使用$store.commit('setUserInfo')来触发mutations中的getUserInfo方法,对于mutations,这里有几点须要注意:ide

  • mutations 中的方法是不分组件的,若是在多个组件中都有setUserInfo,那么执行$store.commit('setUserInfo')的时候会把全部组件中的这个方法都执行,
  • mutations 中的方法最好是同步的,异步的方法有什么问题?没什么问题,可是官方建议咱们将异步的操做放在actions里面去操做

多个 state 的操做 , 使用 mutations 会来触发会比较好维护 , 那么须要执行多个 mutations怎么办?actions登场,前面说过 官方建议咱们在actions里面写异步的代码,那么咱们模拟一下:函数

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        userInfo: {}
    },
    mutations: {
        setUserInfo(state,userInfo) {
            state.userInfo = userInfo
        }
    },
    actions: {
        // commit来自Vuex中上下文context,这里直接使用对象解构,至关于context.commit('setUserInfoAsync',info)
        setUserInfoAsync({commit}){
            setTimeout(()=>{
                let info = {
                    name: 'wfq',
                    age: 26
                }
                commit('setUserInfo',info)
            },2000)
        }
    }
})

复制代码

在store.js中咱们在actions中使用commit来触发mutations里面的方法,这个和上面说的一致,那么咱们怎么触发actions里面的方法:学习

<template>
    <div>
        <div>name:{{$store.state.userInfo.name}}</div>
        <el-button type="primary" size="small" @click="$store.dispatch('setUserInfoAsync')">获取用户信息</el-button>
    </div>
</template>
复制代码

咱们使用dispatch来触发actions里面的方法。

总结

  1. 为何咱们在页面能够直接使用this.$store来触发store.js里面的代码,由于咱们在main.js构建vue的实例的时候已经将store.js引入
  2. state好理解,那么我什么时候该使用mutations,什么时候该使用actions? 同步的方法,咱们放在mutations里面,异步的代码咱们放在actions里面, 触发mutations里面的方法,咱们使用commit,触发actions里面的方法咱们使用dispatch 3.注意:咱们在actions里面的方法,是已经默认携带了上下文context的,固然使用对象解构的话,咱们能够直接使用以下方法来书写代码: functionName({commit,dispatch},param1,param2...){}

mapState、mapGetters、mapActions

若是咱们调用方法,页面上过分使用this.$store.***的话,会显得很累赘,上面三个函数即是Vuex给咱们提供的函数,方便咱们调用store里面的方法 首先记住一点,mapstate和mapGetters放在computed中,mapActions放在methods,记得导入mapState,mapGetters,mapActions,那么咱们以前页面的代码能够改写以下:

store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        userInfo: {}
    },
    getters:{
        getUserInfo(state){
            return state.userInfo
        }
    },
    mutations: {
        setUserInfo(state,userInfo) {
            state.userInfo = userInfo
        }
    },
    
    actions: {
        // commit来自Vuex中上下文context,这里直接使用对象解构,至关于context.commit('setUserInfoAsync',info)
        setUserInfoAsync({commit}){
            setTimeout(()=>{
                let info = {
                    name: 'wfq',
                    age: 26
                }
                commit('setUserInfo',info)
            },2000)
        }
    }
})

复制代码
页面
<template>
    <div>
        <div>name:{{userInfo.name}}</div>
        <el-button type="primary" size="small" @click="getInfo">获取用户信息</el-button>
    </div>
</template>

<script>
    import {mapState,mapGetters,mapActions} from 'vuex'
    export default {
        name: "vuex1",
        data() {
            return {}
        },
        computed:{
        // 这里的mapState对应store.js里面的state,参数是个数组,里面的元素其实就是store.js里面的state里面的数据
            ...mapState([
                'userInfo'
            ]),
        // 这里的mapGetters对应store.js里面的getters,参数是个数组,里面的元素其实就是store.js里面的getters里面的方法
        // mapGetters其实和mapState相似,都是获取state里面的数据,大多数状况,咱们使用mapState便可,这也是为何state.js的
        // 模版代码中没有getters
            ...mapGetters([
                'getUserInfo'
            ])
            
        },
        methods: {
        // 这里的mapActions对应的是store.js里面的actions,参数是个数组,里面的元素其实就是store.js里面的actions里面的方法           
            ...mapActions([
                'setUserInfoAsync'
            ]),
            getInfo(){
            // 调用的方法是mapActions里面的setUserInfoAsync
                this.setUserInfoAsync()
            },
        },
        mounted() {
        }
    }
</script>

<style scoped>

</style>
复制代码

思考一个问题:若是咱们应用须要状态管理的数据过多的时候,写在一个store里面的话就显得太累赘,怎么处理?

这里咱们使用了Vuex的modules,以及namespaced属性,modules容许咱们以modules的形式导出多个store,namespaced:true的话表明 咱们访问store里面的方法时要在对应的命名空间下

下面咱们改写代码,新建store文件夹,在下面新建index.js和modules文件夹,在modules文件夹下面新建一个咱们本身须要的文件夹wfq, 而后在wfq下面新建modules文件夹和index.js,而后在main.js里修改store的路径,目录结构以下图

代码以下:

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import wfq from './modules/wfq'
Vue.use(Vuex)

export default new Vuex.Store({
    modules: {
        wfq
    }
})
复制代码

store/modules/wfq/index.js

// 找出以.js开头的文件
const files = require.context('./modules', false, /\.js$/)
const modules = {}
files.keys().forEach(key => {
    modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default
})
export default {
    namespaced: true,
    modules
}


复制代码

store/modules/wfq/modules/user.js

export default {
    namespaced: true,
    state: {
        userInfo: {name:'WFQ'}
    },
    getters:{
        getUserInfo(state){
            return state.userInfo
        }
    },
    mutations:{
        setUserInfo(state,info){
            state.userInfo = info
        }
    },
    actions: {
        
        setUserInfoAsync({commit}){
            setTimeout(()=>{
                let info = {
                    name: 'wfq',
                    age: 26
                }
                commit('setUserInfo',info)
            },2000)
        }
    }
}

复制代码

接下来看咱们怎么使用:

<template>
    <div>
        <div>name:{{userInfo.name}}</div>
        <el-button type="primary" size="small" @click="setInfo">设置用户信息</el-button>
    </div>
</template>

<script>
    import {mapState,mapActions} from 'vuex'
    export default {
        name: "demo1",
        data() {
            return {}
        },
        computed:{
            ...mapState('wfq/user',[
                'userInfo',
            ]),
        },
        methods: {
            ...mapActions('wfq/user',[
                'setUserInfoAsync',
            ]),
            setInfo(){
                this.setUserInfoAsync();
            },
        },
        mounted() {
        }
    }
</script>

复制代码

使用modules修改后,mapState和mapActions要在第一个参数加上路径,'wfq/user',这也就证实了namespaced的做用

接下来再思考一个问题,若是我在一个store文件(例如user.js)里面想调用另外一个store的方法怎么办,好比,在获得用户的信息后, 我想直接调用该用户的订单信息,而后存储在vuex中怎么办?咱们知道,获取订单信息是一个异步操做,咱们要放在actions里面,而actions里面的 方法怎么触发呢?使用dispatch 咱们新建一个store文件,order.js,此时目录结构以下图

代码以下:

export default {
    namespaced: true,
    state: {
        orderList:[]
    },
    getters:{

    },
    mutations:{

    },
    actions: {
        setOrderListByUser({state},userInfo){
            if(userInfo.name === 'wfq'){
                let orderlist = ['order1','order2']
                state.orderList = orderlist
            }

        }

    }
}
复制代码

下面咱们修改user.js的代码以下:

actions: {
        
        setUserInfoAsync({commit,dispatch}){
            setTimeout(()=>{
                let info = {
                    name: 'wfq',
                    age: 26
                }
                commit('setUserInfo',info)
                dispatch('wfq/order/setOrderListByUser',info,{ root: true })
            },2000)
        }
    }
复制代码

咱们使用dispatch来触发order下面的setOrderListByUser的方法,并传入用户信息,注意:这里要设置{ root: true }, 这样咱们就能在别的页面获取到order.js里面的state下面的orderList的数据了,注意:别忘了去main.js里面修改store的路径

相关文章
相关标签/搜索