Vue2中关于vuex的运用以及异步的坑

499 阅读3分钟

Vue2中关于vuex的运用以及异步的坑

vuex是官方提供的一个插件,状态管理库,集中式管理组件中共用的数据,也是一种组件间通信的方式,且适用于任意组件间通信。

并不是全部项目都需要vuex,如果项目很小,完全不需要vuex,如果项目很大,数据很多,组件很多,维护起来很费劲,那么需要vuex

vuex的基本使用:看回之前的笔记

  • state:仓库储存数据的地方
  • mutations:修改state的唯一手段
  • actions:处理action,书写自己的业务逻辑,也可以处理异步,但不能修改state
  • getters:理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便
  • modules:实现vuex仓库模块式开发存储数据

vuex实现模块开发:如果项目过大,数据很多,接口很多,则根据业务的类型,进行模块封装(vuex进行模块式开发,拆分成多个小仓库)

1.Vuex的搭建

操作大概如下:

main.js引入store

// 引入store
import store from '@/store'
new Vue({
    render: h => h(App),
    router,
    store,
    beforeCreate() {
        Vue.prototype.$bus = this
    }
}).$mount('#app');

建立总仓库 /store/index.js

import Vue from 'vue'
// 引入vuex
import vuex from 'vuex'
// 需要使用一次插件
Vue.use(vuex)
// 引入小仓库
import user from './user/user'
import square from './square/square'
//对外暴露store的一个实例
export default new vuex.Store({
    // 实现vuex仓库模块式开发存储数据
    modules: {
        user,
        square
    }
})

建立分仓库/store/square/square.js

// square小仓库
import { reqAllGoodsList } from '@/api/index'
// state只能由mutations修改,actions获取到的数据用commit提交给mutations
// dispatch是异步操作,用actions接收,actions出来的是promise,需要async await处理
// Category、GoodsCate相关组件需要用到这个的数据,需要挂载
const state = {
    // state中默认初始数据别瞎写,这个是根据接口的返回值去初始化
    allGoodsList: [],
}
const mutations = {
    ALLGOODLIST(state, allGoodsList) {
        state.allGoodsList = allGoodsList
    }
}
const actions = {
    // 通过API里面的接口函数调用,向服务器发请求,获取服务器的数据
    categoryList() {
​
    },
    async allGoodsList({ commit }, pathData) {
        let res = await reqAllGoodsList(pathData);
        if (res.code === 20000) { // 请求成功则提交数据
            commit('ALLGOODLIST', res.data)
        }
    }
}
const getters = {}
export default {
    state,
    mutations,
    actions,
    getters
}

在对应的vue组件中:

computed:{
    ...mapState({
        // 右侧需要的是一个函数,当使用这个计算属性的时候,右侧函数会立即执行一次
        // 注入一个参数state,其实即为大仓库中的数据
        allGoodsList:state => state.square.allGoodsList
    })
},
mounted(){
    // 通知vuex发请求,获取数据,储存于仓库中
    this.$store.dispatch('categoryList')
    // 获取全部商品数据(每次10条数据)
    this.$store.dispatch('allGoodsList',this.pageData)
}

注意:

  1. 在使用上面的函数时,如果需要传递多个参数,需要把多个参数组合为一个对象传入(vuex是不允许多个参数分开传递的)。如此处的pathData:
pageData:{
    // 目前展示的分类id,id=0为默认(全部)
    cateId:0,
    // 页数
    page:1,
    // 每页条数
    limit:10,
}
  1. 使用action时,函数的第一个参数,必须是{commit},即使不涉及到mutations操作,也必须加上该参数,否则会报错。

2.关于异步的坑

dispatch后无法立即获得数据,可以在后面.then()进行获取。

比如,我们在mounted()中派发获取商品详情,并通过映射获取detail和imgList

computed:{
    ...mapState({
        goodDetail:(state) => state.good.goodDetail
    }),
    ...mapGetters(['goodImageList']),
},
mounted() {
    // 派发获取商品详情
    this.$store.dispatch('goodDetail',this.$route.params.id)
}

在仓库中:

const state = {
    goodDetail: {},
}
const mutations = {
    GOODDETAIL(state, goodDetail) {
        state.goodDetail = goodDetail
    }
}
const actions = {
    async goodDetail({ commit }, id) {
        const res = await reqGoodsDetail(id)
        if (res.code === 20000) { // 请求成功则提交数据
            commit('GOODDETAIL', res.data.goodsInfo)
            console.log(res.data.goodsInfo)
            return 'ok'
        } else {
            return Promise.reject(new Error('获取商品详情失败'))
        }
    }
}
const getters = {
    goodImageList(state) {
        console.log(String(state.goodDetail.image).split(',') || [])
        return String(state.goodDetail.image).split(',') || []
    },
}
​

控制台:

image.png

出现undefined,是因为state和getter的映射不能同时进行,getter映射在获取时,state还是空的,赋值为undefined,得等待state中的detail获取到才能进行获取。

所以得进行异步处理,等待detail派发完成再获取imgList,此处使用then处理

computed:{
        ...mapState({
            goodDetail:(state) => state.good.goodDetail
        }),
    },
    methods:{
        // 处理ImageStr,将其分割成数组
        getGoodImageList(ImageStr){
            return String(ImageStr).split(',') || []
        }
    },
    mounted() {
        // 派发获取商品详情
        this.$store.dispatch('goodDetail',this.$route.params.id).then(()=>{
            this.goodImageList = this.getGoodImageList(this.$store.state.good.goodDetail.image)
        })
        ...
    }

3.async await使用

async await用来处理返回的promise对象,比如处理axios异步请求,在vuex仓库中的actions大量用到。

    async goodDetail({ commit }, id) {
        const res = await reqGoodsDetail(id)
        if (res.code === 20000) { // 请求成功则提交数据
            commit('GOODDETAIL', res.data.goodsInfo)
            return 'ok'
        } else {
            return Promise.reject(new Error('获取商品详情失败!'))
        }
    },

await含义是async标识的函数体内的并且在await标识代码后面的代码先等待await标识的异步请求执行完,再执行。这也使得只有reqGoodsDetail执行完,res得到返回值后,才会执行后面的输出操作。

什么时候适合用async await,什么时候用then,还是需要注意一下。

个人是认为,如果有一连几个异步操作就用async await,或者是像在method,actions里面的异步函数。如果有单个,或者某些代码必须建立在某个异步操作的基础上(也就是说,只有执行了这一步,才能执行下面几步,用then),像这样:

this.$store.dispatch('getUserInfo').then(()=>{
    sessionStorage.setItem('id',this.$store.state.user.userInfo.id)
})

async await总之就是来简化then链的,还要注意用try catch进行捕获异常,相关的其他知识点就看笔记了。