必备-12.vuex

必备-12.vuex

vuex:状态管理库**(公共大仓库)**,集中式存储管理所有组件的状态值,相当于把所有Vue组件的状态数据放到一个公共数据库中,任何一个组件修改了公共数据库中的状态值,其他使用了该状态值的组件都会跟着刷新渲染这个值

  • Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源“而存在。这也意味着,每个应用将仅仅包含一个 store 实例

  • vuex的作用

    • 1、vuex是专为Vue.js应用程序开发的状态管理模式(集中式存储)—>公共仓库
    • 2、缓存 keep-alive
      • localStorage:本地存储,刷新有数据、数据永久
      • sessionStorage:会话存储,刷新有数据、关闭页面没有数据
      • vuex:不刷新,不关闭页面,就会保存以前的数据,刷新就不存在数据
  • vuex:“单向数据流”理念

    • image-20211210181113883
  • vuex的异步函数执行的过程:

    • image-20211210100524034

vuex的五个核心属性

  • state:相当于vue中的data

  • getters:相当于vue中的computed

  • mutations:相当于vue中的methods(同步)

  • actions:相当于vue中的methods(异步)

  • Modules:模块

  • 在讲解vuex的五个核心属性之前需要先创建一个vuex仓库的实例:

    • //1、新建index.js
      import Vue from 'vue'
      import Vuex from 'vuex'
      Vue.use(Vuex)//在vue上挂载vuex包,扩展vuex插件
      
      const store = new Vuex.Store({//创建Vuex的store实例
        state: {
          count: 0
        },
        mutations: {
          increment (state) {
            state.count++
          }
        }
      })
      export default store;
      
      //2、在main.js中挂载,注意,这个store实例是挂载到了Vue的prototype上
      new Vue({
        el: '#app',
        store: store,
      })
      
state
  • state:相当于vue中的data

  • 作用:存放所有组件能够共用的状态值

  • 用法

    • vuex实例仓库端定义

      • const store = new Vuex.Store({
          	//在大仓库中存放一个count为0
           state: {
            count: 0
          }
        })
        
    • 所有vue组件端调用

      • //方式一:直接沿着原型链调用(不推荐没缓存)
        	{{this.$store.state.count}}
        //方式二:放到computed中调用(有缓存)
        	  computed: {
            	count () {
              	return this.$store.state.count
            		}
          		}
        //方式三:使用辅助方法,放到computed中调用多个(推荐,有缓存)
        	import { mapState } from 'vuex'//导入辅助函数Vuex.mapState,它返回的是一个对象
        	//第一种:计算属性中只存在映射过来的,参数是数组或对象,以数组为例:
        	computed: mapState(['count'])// 映射 this.count 为 store.state.count
        	//第二种:计算属性中存在映射过来的也存在自定义的,参数是数组或对象,以对象为例:
        	computed: {
          		addCount(){},
          		// 使用对象展开运算符将此对象混入到外部对象中
          		...mapState({
         			//...
          			})
        		}
          
        
        	
        
getters
  • getters:相当于vue中的computed

  • 作用:在vue组件获取state状态值之前,对状态值做格式化,再传给vue组件

  • 参数

    • state:【默认参数】指向的是vuex的实例store里的state
    • getters:【默认参数】指向的是vuex的实例store里的getters,可以根据它,获得getters中其他属性的信息
  • 用法

    • vuex实例仓库端定义

      • getters: {
          getCountAdd: (state,getter )=> {
            return state.count+1+getter.getc;//0+1+666
          }
          getc(){return 666}
        }
        
    • 所有vue组件端调用:在computed中调用

      • import { mapGetters } from 'vuex';//导入辅助函数
        //方式一:以数组作为参数执行辅助函数
        	  computed: {
         		 // 使用对象展开运算符将 getter 混入 computed 对象中
            		...mapGetters([
              			'getCountAdd',
              			'getc',
              			// ...
            	])
          		}
        //方式一:以数组作为参数执行辅助函数,可以自定义状态名
        		computed: {
        			...mapGetters({
         			 // 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
          			doneCount: 'doneTodosCount'
        			})
        		}
        
        
mutations
  • mutations:相当于vue中的methods(同步)

  • 要点:mutations中的函数必须是同步的,不能放异步方法

  • 作用:vue组件不能直接修改store大仓库中的状态值,(会导致页面与仓库不同步),如果想做到所有组件数据,与store内state状态值同步,就要经过mutations中的方法来修改

  • 参数

    • state:【默认参数】指向当前vuex实例store的state对象
    • payload:载荷,【第二个参数】用来接收组件传给函数的参数,如果想传多个数据,载荷应该是一个对象
    • 第三个及以后的参数不会发送给mutations里的方法
  • 用法

    • vuex实例仓库端定义

      • mutations: {
        	//自增函数
          increment (state, payload) {
            state.count += payload.amount
          }
        }
        
    • 所有vue组件端调用:在methods中调用,

      • //方式一:使用store.commit方法可直接调用
        methods:{
            addCount(){
               this.$store.commit('increment', {
          		amount: 10
        		})
            }
        }
        
        //方式二:使用辅助函数,参数为对象或数组
        import {mapMutations} form "vuex";//导入vuex的辅助函数
        methods:{
            ...mapMutations(["increment"]),//数组传参
                ...mapMutations({//对象传参
                inc:"increment"
            })
        }
        	
        //调用
        	<telement>
               <div> 
               <button @click="inc(1,2,3)">点击 </button>
                </div>
            </telement>
        
actions
  • actions:相当于vue中的methods(异步)

  • 作用:mutation只能存储同步函数,actions就是将同步函数封装为异步函数

    • Action 提交的是 mutation,而不是直接变更状态。
    • Action 可以包含任意异步操作。
  • 参数

    • context:【默认参数】指向vuex的实例store大仓库
  • 用法

    • vuex实例仓库端定义

      • const store = new Vuex.Store({
          state: {
            count: 0
          },
          mutations: {
            increment (state) {
              state.count++
            }
          },
          actions: {
              //定义自增方法
            increment (context) {
            	//异步函数
            	setTimeOut(function(){
            	//内部再调用了commit方法
            	 context.commit('increment')
            	},1000)
             
            }
          }
        })
        
    • 所有vue组件端调用:在methods中调用

      • //方式一:使用store的dispatch方法调用触发
        	methods:{
        		addCount(){
        			this.$store.dispatch('increment')
        		}
        	}
        //方式二:使用辅助函数,参数为对象或数组
        import {mapActions} form "vuex";//导入vuex的辅助函数
        methods:{
            ...mapActions(["increment"]),//数组传参
                ...mapmapActions({//对象传参
                inc:"increment"
            })
        }
        	
        //调用
        	<telement>
               <div> 
               <button @click="inc(1,2,3)">点击 </button>
                </div>
            </telement>
        
modules
  • 作用:减少单一状态树的shore对象存放数据导致的臃肿,将整个sotre对象拆分为多个模块module,每个模块都存在自己局部的state、getters、mutations、actions、namespaced,甚至仍然将这个模块继续向下拆分

  • namespaced:默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。

    • 如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。

    • 我们在...mapGetters("moduleA",["msg"]),寻找的是moduleA模块中的msg状态值,如果没有写moduleA的话,它会直接去全局的store中找状态值msg

  • 用法

    • 第一步:需要创建一个独立的模块:

      • //store/moduleA.js
        	//就是vuex实例类型的对象
        	const mouduleA={
        		//存在state,mutations,actions,getters,namespaced。。。
        		
        		state:{
        			msg:"我是moduleA",
                    arr:[1,2,3,4,5,6]
        		},
                getters:{
                    getNum(state){
                        return state.arr.filter(item=> item%2==0)
                    }
                }
        	}
        	//导出模块
        	export default moduleA;
        
    • 第二步:在store实例中导入并挂载:

      • modules: {
          a:moduleA
        }
        })
        //重点:
        //store挂载moduleA之后:
        	//moduleA中的state对象会挂载到store的state对象上
        	store:{
                state:{
                    a:{//重点:a指向的就是moduleA模块中的state对象
                        msg:"我是moduleA";
                    }
                }
            //moduleA中的mutations、getters、actions对象会挂载到store的对应对象上
             //以getters为例
            store:{
                getters:{
                    "a/getNum":[2,3,4];//将子模块中计算属性的计算结果放入getters中
                }
                //mutations、actions相同做法
            }
                
            }
        
    • 第三步:在vue组件中调用vuex的modules中:

      • //方式一:通过$store导入
        	this.$store.state.a.msg;//获取a模块中的属性
        	this.$store.getters["a/getNum"];//获取方法或计算属性
        //方式二:通过辅助函数写法(常用)
        	import {mapState,mapGetters} from "vuex";
        	computed:{
                ...mapState("a",["msg"]),//a是nameSpace的命名空间,所以必须开启namespace才行
                ...mapState(["a/msg"]),//这样获取不了,因为state的挂载方式不是这样挂载的
                ...mapGetters(["a/getNum"]),//这样能获取,以为getters、mutations、actions的挂载方式
                    
            }
        //方式三:通过导入方法指定mapxxx的地址
         	import { createNamespacedHelpers } from 'vuex'
        	const { mapState, mapActions } = createNamespacedHelpers('a')
            	computed:{
                ...mapState(["msg"]),//它会直接找a里的msg,因为上面设置了命名空间
            }
            
        

辅助函数

mapState()获取的是大仓库state属性中的状态值

mapGetters()获取的是大仓库getters属性中的状态值

mapMutations()获取的是大仓库mutations属性中的方法

mapActions)获取的是大仓库actions属性中的方法

mapState()
  • 在真实项目中我们不会使用{{this.$store.state.count}}来调用仓库中的状态值,以为这样每次页面渲染或打开页面都需要去大仓库中获取(无缓存)

  • 所以我们基于computed(有缓存)的优势,来获取仓库中的数据,这时就需要调用到vuex中内置的辅助函数:mapState();

  • 第一步:导入mapState辅助函数

    • //Home.js
      	import mapState from "vuex";
      
  • 第二步:在计算属性computed中配置mapState,mapState返回的是一个对象

    • mapState(param):辅助函数的参数可以是对象或数组

      • 对象可以自定义获取的状态值名,数组就是仓库中状态名是啥,我们调用就得用啥状态名
    • 方式一:computed中只需要大仓库中的mapState

      • //1、mapState函数中的参数是数组,会默认返回对应的num和age状态值,我们调用时也直接调用num age即可
        computed:mapState(["num","age"])
        //2、mapState函数中的参数是对象,会默认返回对应num和age状态值,并且赋值给调用方的私有属性n和a,我们调用时用n和a调用
        	computed:mapState({
              n:"num",
              a:"age"
          		})
        
    • 方式二:computed中既有自己定义的计算属性,又用辅助函数获取的

      • computed:{
             getData(){
               return aaa;
             },
             //因为mapState中获取的是对象,所以需要通过展开运算符将其展开
             ...mapState(
               ["num","age"]
             )
           }
        
    • 注意:mapState获取的是对象,需要展开运算符展开

mapGetters()

mapGetters()获取的是大仓库getters属性中的状态值(必须是同步的方法)

  • vuex实例的getters属性相当于vue实例中的computed属性

  • 第一步:在vuex实例中添加getters属性,并定义格式化方法:

    • //store/index.js   
      	getters:{
                  //第一个参数是当前vuex实例的state属性对象
                  //第二个参数是当前vuex实例的getters属性对象
                  addCount(state,getters){
                      return state.count++;
                  }
              }
      
  • 第二步:在调用方实例中导入,并引入

    • //Home.vue
      	import mapGetter from "vuex";//导入mapGetter
      	
      	
      	computed: {
      		//方式一:直接在computed中调用:通过Vue公有属性中挂载的$store调用
        		addCount () {
          	return this.$store.getters.addCount
        		}
        		//方式二:通过mapGetter调用
                  ...mapGetters(["addCount"]);//数组参数形式获取,不能改状态名
              	...mapGetters({
                      add:"addCount";//对象形式获取,可以改状态名
                  })
                 
      	}
      	
      	
      
mapMutations()
  • mapMutations()获取的是大仓库mutations属性中的状态值

  • **第一步:**在vuex中创建mutations属性

    • mutations: {
        addCount (state) {
          // 变更状态值
          state.count++
        }
      
  • 第二步:在Home.vue中导入mapMutations并注册到实例methods上

    • export default {
        // ...
        methods: {
          ...mapMutations([
            'addCount', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
          ]),
          ...mapMutations({
            add: 'addCount' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
          })
        }
      }
      
mapActions()
  • mapActions获取的是大仓库actions属性中的方法

  • 第一步:在vuex实例中添加actions方法(必须是异步的):actions的作用就是将mutations里的同步方法异步化

    • //store/index.js  
      actions: {
          //context是指向当前vuex实例的对象,也就是$store,所以能调用它上面的所有方法
         increment (context) {
           context.commit('addCount')
         }
       }
      
  • 第二步:在Home.vue中导入,并注册到自己身上

    • import { mapActions } from 'vuex'
      
      export default {
        // ...
        methods: {
          ...mapActions([
            'addCount', // 将 `this.addCount()` 映射为 `this.$store.dispatch('addCount')`
      
            // `mapActions` 也支持载荷:
            'addCount' // 将 `this.addCount(amount)` 映射为 `this.$store.dispatch('addCount', amount)`
          ]),
          ...mapActions({
            add: 'addCount' // 将 `this.add()` 映射为 `this.$store.dispatch('addCount')`
          })
        }
      }
      

vuex缓存

  • 问题:没有用缓存之前,我们每次打开页面都会发送请求

  • 目标:应用vuex实现缓存,只要页面不刷新,不关闭,数据如果是null,我就发送请求,如果不是null就从vuex的缓存中拿数据

  • 实现

    • 第一步:创建异步方法获取服务器数据,并把数据赋值给状态值

      • //index.js
        import Vue from 'vue'
        import Vuex from 'vuex'
        import moduleA from './moduleA/moduleA'
        import api from "@/api/index.js";
        Vue.use(Vuex)
        //store实例
        export default new Vuex.Store({
          state: {
            // 第一步:list专门存放数据
            list:null
          },
          mutations: {
            // 第二步:修改list的值,如果请求成功就不为null了
            changelist(state,payload){
              state.list=payload;
            }
          },
          actions: {
            //第三步:异步函数需要写在actions中
            async  getData(context){
                let result=await api.getTaskList();
                if(result.code===0){//返回数据成功
                  context.commit("changelist",result.list);//异步函数想修改state状态值,必须经过mutations
                }
            }
        
          },
          modules: {
            a:moduleA
          }
        })
        
    • 第二步:在页面加载之前,先判断是否有缓存,如果有直接用

      • //Three.vue
        	<template>
        	<div class="three">
        		{{this.$store.state.list}}
        	</div>
        </template>
        
        <script>
        	export default{
        		name:"Three",
        		data(){
        			return{
        			}
        		},
        		created(){
        			if(!this.$store.state.list){//只要list是null,表示没缓存,向服务器端发请求
        				this.getData();
        			}
        			//否则直接调用list即可
        		},
        		methods:{
        			async getData(){
        				let result= await this.$api.getTaskList();
        				console.log(result);
        			}
        		}
        	}
        </script>
        
        <style>
        </style>
        
        

vuex的使用步骤

  • 第一步:安装vue和vuex模块包:$npm i vue vuex -S

  • 第二步:导入vue和vuex

    • //为了防止导入的包太大,所以按需导入
      //  /store/index.js
      	import vue from "vue";
      	import Vuex from "vuex";
      
  • 第三步:Vue注册vuex并导出

    • //  /store/index.js
      	import vue from "vue";
      	import Vuex from "vuex";
      	//Vue注册Vuex
      	Vue.use(Vuex)
      	//创建vuex的实例
      	const store = new Vuex.Store({
        		state: {
         	 	count: 0
        				},
        		mutations: {
         			 increment (state) {
            		state.count++
          					}
        					}
      			})
          //导出创建好的vuex实例
          export  default store;
      
  • 第四步:在main.js中导入、挂载已经创建好的实例

    • //main.js
      import store from "@/store/index.js";
      
      new Vue({
        router,
        //store被挂载到了全局Vue实例的prototype上,任何实例都可以利用this.$store获取到store大仓库实例
        store,
        render: h => h(App)
      }).$mount('#app')
      
  • 第五步:任意组件可以调用修改仓库中的信息,但是想修改数据,都必须通知仓库(调用仓库mutations)中的方法,来实现页面数据与仓库数据的同步修改

    • 面试题:能不能在界面上直接修改仓库中获取的数据:能!,但是修改的数据只是在页面上显示修改了,因为没有经过仓库,仓库中的数据实质上并没有修改,所以我们在工作中不能直接修改仓库中获取的值。

    • //Home.vue
        <div class="home">
             {{this.$store.state.count}}//调用大仓库中的count
            <button @click="changeData">add</button>//修改仓库中的count
        </div>
      <script>
          	methods:{
             //Home.vue
          	changeData(){
            	//使用store.commit来执行store中mutations中的方法
            	store.commit('increment')
         		 }
              }
      </script>
      
      
    • //  /store/index.js
      	const store = new Vuex.Store({
              
            	state: {
             	 //放到大仓库中的状态值,所有组件都可以用这个count
             	 count: 1000
                    },
      		//存放方法(同步)
            mutations: {
      			//状态值自增的方法
                  increment (state) {
                state.count++
                          }
                        }
              })
      	
      
    • image-20211210104851749

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值