vuex是什么, state,getters,mutation,action,modules的用途和用法

vuex是什么, state,getters,mutations,actions,modules的用途和用法

vuex 是一个状态管理工具,它采用集中式存储管理应用的所有组件的状态,当有多个组件共享数据时,如果需要构建是一个中大型单页应用,会考虑如何更好地在组件外部管理状态,就使用Vuex 。

好处:

①: 能够在 vuex 中集中管理共享的数据,易于开发和后期维护 ②: 可以做状态管理、采用localstorage保存信息、数据一直存储在用户的客户端中 ③: 存储在 vuex 中的数据都是响应式的,能够实时保持数据与页面的同步,能够高效地实现组件之间的数据共享,提高开发效率

vuex核心:

state:vuex的基本数据,数据源存放地,数据是响应式的,用于定义共享的数据。

getter:可以对state进行计算操作,主要用来过滤一些数据,可以在多组件之间复用

mutation:提交更新数据的方法,唯一 一个可以操作state 中数据的方法,必须是同步的,第一个参数是state,第二个参数是commit传过来的数据

action:action是用来处理数据的方法变成异步操作的,一般用来发请求,在 action 中写入函数,然后在页面中用store.dispatch调用,然后在 action 中通过commit 去调用 mutation 通过 mutation 去操作state,进行修改数据。

modules:模块化vuex,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理

用法

引入vuex

开发依赖 : npm i xxxx --save-dev ; npm i xxxx -D ;

生产依赖: npm i xxxx --save ; npm i xxxx -S; npm i xxxx;

//引入Vue
import Vue from 'vue'
// 引入vuex
import store from '@/store';
//创建Vue实例对象---vm
new Vue({
  el:'#app',
  render: h => h(App),
  // 注册仓库:组件实例身上会多一个属性$store属性
  store
})

单独小仓库

import { reqCartList,reqDeleteCartById,reqUpdateCheckedByid } from "@/api";
const state = {
     //当前临时用户的购物车的数据
    cartList: [],
};
const mutations = {
    // 2 赋值给state里面的数据
    GETCARTLIST(state,cartList){
        // console.log(state,'数据源');
        state.cartList = cartList;
    }
};
const actions = {
    //一定要切记:action第一个参数(minStore) 第二个参数:dispatch的载荷(传递过来的数据)
    // 1 获取购物车列表数据
    async getCartList({ commit }){
        let result = await reqCartList();
        // console.log(result.data,123);
        if(result.code == 200){
            // 转发通知
            commit("GETCARTLIST",result.data);
        }
    },
    // 删除购物车某一个产品
    async deleteCartListBySkuId({ commit },skuId){
        let result = await reqDeleteCartById(skuId);
        if (result.code == 200) {
            return "ok";
          } else {
            return Promise.reject(new Error("faile"));
          }
    },
    // 修改购物车某一个产品的选中状态
    async updateCheckedById({ commit },{ skuId,isChecked }){
        let result = await reqUpdateCheckedByid(skuId, isChecked);
        if(result.code == 200){
            return "ok";
        }else{
            return Promise.reject(new Error("faile"));
        }
    },
    //删除全部勾选的产品,因为只有一次性删除一个商品的接口所以这样写,这个action调用另一个action方法多次
  deleteAllCheckedCart({ dispatch, getters }) {//context小仓库
    //context:小仓库包含commit【提交mutations修改state】 getters【计算属性】 dispatch【派发action】 state【当前仓库数据】属性,action里面都可以拿到
    //获取购物车中全部的产品(是一个数组)
    let PromiseAll = [];
    getters.cartList.cartInfoList.forEach((item) => {
        console.log(item);
      // 调用其他action方法,返回值是一个promise
      let promise = item.isChecked == 1 ? dispatch("deleteCartListBySkuId", item.skuId): "";
      //将每一次返回的Promise添加到数组当中
      PromiseAll.push(promise);
    });
    // Promise.all([p1,p2,p3]),p1|p2|p3:每一个都是Promise对象
    //只要全部的p1|p2....都成功,返回结果即为成功
    //如果有一个失败,返回即为都失败失败结果
    return Promise.all(PromiseAll);
  },
    //修改全部的产品的选中状态的方法
    //在action当中如何获取到仓库中的存储的数据
    //1:获取到全部购物车的数据【数组:六个元素】
    //2:触发updateChecked这个action六次【全部产品都修改了】
    //3:updateAllCart,返回一个Promise,告诉组件成功了,还是败了【组件才能继续写别的业务】
  updateAllCartIsChecked({ dispatch, state,getters }, isChecked) {
        //数组  //遍历购物车里面产品:购物车里面有多少产品,回调就执行多少次
        let promiseAll = [];
        state.cartList[0].cartInfoList.forEach((item) => {
            console.log(item);
            let promise = dispatch("updateCheckedById", {
            skuId: item.skuId,
            isChecked,
            });
            promiseAll.push(promise);
        });
        // 另一种写法:可能死循环
        // getters.cartList.cartInfoList.forEach(item =>{
        //     //在当前action内部,调用内部action执行N次
        //     let promise = dispatch("updateCheckedById", {
        //         skuId: item.skuId,
        //         isChecked,
        //         });
        //         promiseAll.push(promise);
        // })

        //如果不书写return,返回结果永远undefined,永远是真
        //Promise.all执行,参数需要的是一个数组,数组里面每一个都是promise,如果都成功,promise返回即为成功结果
        //如果有一个【修改状态】promise失败返回的结果即为失败
        return Promise.all(promiseAll);//可以保证 updateAllCart返回的是promise【成功、失败】
  },
}
const getters = {
    // 3 简化购物车数据要数据的第0项
    cartList(state) {
      return state.cartList[0] || {};
    },
  };
export default {
    state,
    mutations,
    actions,
    getters
}

state

组件访问state数据的第一种方式

使用公共数据

在组件中,通过this.$store.state.属性名访问。

在模板中,则可以省略this而直接写成:{{$store.state.属性名}}

组件访问state数据的第二种方式

基于vuex提供的mapState辅助函数,可以方便的把store中指定的数据,映射为当前组件的计算属性

//1.按需导入辅助函数mapState
import { mapState }from 'vuex'

export default {
    name: 'left',
    computed: {
    // 拿到数据
    ...mapState({
      // 右侧需要的是一个函数,当使用这个计算属性的时候,右侧函数立即执行一次
      // 注入一个参数state,其实即为大仓库中数据
      // categoryList:(state)=>{
      //   // console.log(state);
      //  return state.homo.categoryList;
      // }
      categoryList: state => state.home.categoryList
    })
  },
}

//页面使用
<div
class="item bo"
v-for="(c1, index) in categoryList"
:key="c1.categoryId"
:class="{ cur: currentIndex == index }"
 @mouseenter="changeIndex(index)"
>                

mutations修改公共数据

它是Vuex中用来修改公共数据的唯一入口。

在定义时:它的第一个参数是state,第二个参数是载荷commit传过来的数据接收

注意:mutations必须是同步函数,mutation里面不能放异步代码,第二个参数是可选的,表示载荷,是可选的。

**第一种方式:**这里的commit是固定的方法

在调用时:用 this.$store.commit(‘mutation名’, 载荷) 来调用

第二种方式:

在action里面转发通知

const state = {
     //当前临时用户的购物车的数据
    cartList: [],
};

const mutations = {
    //第二个参数接收commit传过来的数据
    GETCARTLIST(state,cartList){
        // 2 赋值给state里面的数据
        // console.log(state,'数据源');
        state.cartList = cartList;
    }
};

const actions = {
    //一定要切记:action第一个参数(minStore) 第二个参数:载荷(传递过去的数据)
    // 1 获取购物车列表数据
    async getCartList({ commit }){
        let result = await reqCartList();
        // console.log(result.data,123);
        if(result.code == 200){
            // 转发通知
            commit("GETCARTLIST",result.data);
        }
    },
}    

第三种:mapMutations 辅助函数

基于 Vuex 提供的 mapMutations 辅助函数,可以方便的把 Store 中指定的方法,映射为当前组件的 methods

//1.按需导入mapMutations辅助函数
import { mapMutations } from 'vuex';
export default {
    name: 'right',
    methods: {
        //2.从vuex中把add映射为当前组件的methods方法
        //...mapMutations({'新名字': 'mutation名'})
        ...mapMutations(['add'])
    }
}
mutaions拓展理解
问:为啥是$store.commit('mutations的名字')而不是$store.mutations的名字()?

答:Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler) 。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。

问:数据不可以该在组件内部直接修改吗?

答:不能。虽然语法上不报错,也有响应式的特点。但是不推荐。特别是在严格模式下会报错。若将vue创建 store 的时候传入 strict: true, 开启严格模式,那么任何修改state的操作,只要不经过 mutation的函数,vue就会报错

问:可以传递多个数据吗?

答:参数只能有一个:下面的写法是不对的:

this.$store.commit('setUrl', url, host) // host这个参数将无法被接收到
如果希望传递复杂的数据,第二个参数可以是对象或者数组,例如下面的写法

this.$store.commit('setUrl', { url, host} )
问:等价写法 this.$store.commit({type: 'mutations的名字'})

action

  • 作用:发异步请求获取数据,调用mutations来保存数据,将整个ajax操作封装到Vuex的内部
  • 要点:
  • action 内部可以发异步请求操作,action是间接修改state的,是通过调用 mutation来修改state

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wMbJCaVs-1660634474344)(vuex状态管理.assets/image-20220816151336583.png)]

第一种方式:在组件中通过this.$store.dispatch(‘action名字’,参数)来调用action

mounted() {
      this.getDate();
    },
methods: {
      // 1 获取个人购物车数据
      getDate(){
        this.$store.dispatch("getCartList");
      },
}        

第二种方式:基于vuex提供的mapActions辅助函数,可以方便把store中指定的action,映射为当前组件的methods

methods: { 
    //...mapActions(['actions名']), 
    ...mapActions({'新名字': 'actions名'}) 
}

getters

作用:它是 Vuex 中的计算属性,当 Store 数据源发生变化时,Getter 的返回值会自动更新,常用来简化数据。

第一种方式:

使用格式

在组件中通过:$store.getters.getter的名字 来访问

第二种方式 :

基于 mapGetters 辅助函数,可以把 store 中的 getter 映射为当前组件的计算属性。

import { mapGetters } from "vuex";

// 获取getters的数据
    computed:{
      //...mapGetters({'新名字': 'xxx'})
      ...mapGetters(['categoryView','skuInfo','spuSaleAttrList']),
      // 给子组件的数据
      skuImageList(){
        // console.log(this.skuInfo.skuImageList,'skuImageList');
        // 从Getters传递过来的skuInfo上拿放大镜图片数据
        //如果服务器数据没有回来,skuInfo这个对象是空对象,防止在undefined身上点数据
         return this.skuInfo.skuImageList || [];
      }
    },

modules

import Vue from 'vue';
import Vuex from 'vuex';
// 需要使用插件一次
Vue.use(Vuex);

// 引入vue的每个小仓库
import home from './home';
import search from './search';
import detail from './detail';
import shopcart from './shopcart'
import user from './user'
import trade from './trade'

// 对外暴露store类的一个实例
export default new Vuex.Store({
    // 实现Vuex仓库使用模块式开发存储数据
    modules:{
        home,
        search,
        detail,
        shopcart,
        user,
        trade
    }
})

modelues拓展理解

问题导入

所有的全局数据、方法都集中在了一起,导致 Vuex 的结构混乱,不利于现阶段的开发和后期的维护

modules的作用

拆分模板,把复杂的场景按模块来拆开

export default new Vuex.Store({
  // state: 用来保存所有的公共数据
  state: {},
  getters: {},
  mutations: {},
  actions: {},
  modules: {
    模块名1{
            // namespaced为true,则在使用mutations时,就必须要加上模块名
        namespaced: true, 
          state: {},
            getters: {},
            mutations: {},
            actions: {},
            modules: {}
    },
    模块名2{
        // namespaced不写,默认为false,则在使用mutations时,不需要加模块名
          state: {},
            getters: {},
            mutations: {},
            actions: {},
         modules: {}
    }  
  }
})

也可以进一步对文件进行拆分

|--store /
|------- index.js # 引入模块
|------- modules
|-------------- / mod1.js # 模块1
|-------------- / mod2.js # 模块2

访问数据和修改数据的调整

  • 访问模块中的数据,要加上模块名
获取数据项:  {{$store.state.模块名.数据项名}}
获取getters: {{$store.getters['模块名/getters名']}}

访问模块中的mutations/actions:

  • 如果namespaced为true,则需要额外去补充模块名
  • 如果namespaced为false,则不需要额外补充模块名
$store.commit('mutations名')        // namespaced为false
$store.commit('模块名/mutations名')  // namespaced为true

小结

使用了modules之后,在访问数据时就要额外添加modules的名字了。

----------- / mod2.js # 模块2


### 访问数据和修改数据的调整

- 访问模块中的数据,要加上模块名

```js
获取数据项:  {{$store.state.模块名.数据项名}}
获取getters: {{$store.getters['模块名/getters名']}}

访问模块中的mutations/actions:

  • 如果namespaced为true,则需要额外去补充模块名
  • 如果namespaced为false,则不需要额外补充模块名
$store.commit('mutations名')        // namespaced为false
$store.commit('模块名/mutations名')  // namespaced为true

小结

使用了modules之后,在访问数据时就要额外添加modules的名字了。

结论: 在使用modules时,建议都给加上namespaced!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值