vue状态管理

状态管理


vuex是一个专门为Vue.js应用程序开发的 状态管理模式
采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vue为这些被多个组件频繁使用的值提供了一个统一管理的工具——VueX。
在具有VueX的Vue项目中,我们只需要把这些值定义在VueX中,即可在整个Vue项目的组件中使用。

  • 小型项目(不适用于vuex)
  • 中小型项目(有store模式)
  • 中大型项目(vuex 可以分模块)

状态管理模式

状态管理模式包含以下部分:

  • state 驱动应用的数据源
  • view 以声明的方式将state映射到视图
  • actions 响应在view上的用户输入导致的状态变化
    vue状态管理我们把组件的共享状态抽取出来,以一个全局单例模式管理
    在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为。

使用vuex的情况

Vuex 可以帮助管理共享状态。

中小型项目,不是特别庞大,使用vuex比较冗余,可以使用store模式。
需要构建一个中大型的单页应用,可以使用vuex进行组件外部的状态管理。

简单的store模式

utils文件夹中新建store.js 做为临时仓库

export default{
    debug:true,
    state:{
        msg:"is store",
        name:'zhangsan'
    },
    actions:{
        getname(){
            console.log('zhangsan');
        }
    }
}

在组件中获取store仓库里的数据和方法
Home.vue

<template>
  <!-- {{state.msg}} -->
  <!-- <button @click="getname">点击</button> -->
</template>
<script>
	import store from '../utils/store'
	export default {
	  data(){
	    return{
	      state:store.state
	    }
	  },
	  methods:{
	    ...store.actions
	  }
	}
</script>

单一状态树

vuex使用单一状态树,一个对象就包含了全部的应用层级状态。
每一应用只包含一个store实例。
单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。

vuex安装与使用

安装vuex

npm i vuex -s

初始化

store 文件夹下 新增文件 index.js

import { createStore } from 'vuex'
export default createStore({
  state: {
  	msg:'is store',
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})

将store挂载到当前项目的vue实例中

main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

createApp(App).use(store).use(router).mount('#app')

在组件中使用vuex

State

存放数据

state: {
	  	msg:'is store',
	  	...
},

组件中使用
Home组件

方法一:

<template>
        {{$store.state.msg}} //一般不这样使用
</template>

方法二:计算属性方法

<template>
        {{msg}}; //官方推荐使用方式
</template>
<script>
 export default{
  computed:{
  	msg(){
  		return  this.$ store.state.msg; //官方推荐使用
  	}
    }
  }
 </script>

方法三:辅助函数(项目中常用方法)

<template>
        {{msg}}; 
</template>
<script>
import {{mapState}}  from 'vuex'  //辅助函数
 export default{
   computed:{
  		...mapState(['msg']),
   },
  }
 </script>

getters

Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。
就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
定义

  state: {
    books:['js01','js02','js03'],
  },
  getters:{
    GET_BOOK_NUM:(state,getters)=>{
      return state.books.length
    }
  },

使用
方法一:不推荐使用

<template>
{{$store.getters.GET_BOOK_NUM}}
</template>

方法二:计算属性方法

<template>
{{GET_BOOK_NUM}}
</template>
computed:{
    GET_BOOK_NUM(){
      return this.$store.getters.GET_BOOK_NUM
    }
}

方法三:辅助函数(项目中常用方式)

<template>
{{GET_BOOK_NUM}}
</template>
import {mapGetters} from 'vuex'
computed:{  
      ...mapGetters(['GET_BOOK_NUM'])  
}

mutations

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

  • 无传参

定义

 state: {
	   num:0
	 },
mutations: {
    add(state){
      state.num++;
    }
 },

使用
方法一:传统用法

<template>
{{num}}
<button @click="add">+</button>
</template>
methods:{
    add(){
      this.$store.commit('add')
    }
}

方法二:辅助函数

<template>
	{{num}}
	<button @click="add">+</button>
	</template>
	import {mapMutations} from 'vuex'  //辅助函数
	methods:{
	    ...mapMutations(['add'])
	}
  • 传参

定义

    state: {
	   num:0
	 },
	mutations: {
	    add(state,n){
	      state.num+=n;
	    }
     },

使用
方法一:

   <template>
	{{num}}
	<button @click="add(2)">+2</button>
   </template>
	add(){
      this.$store.commit('add',2)
     },

方法二:

   <template>
	{{num}}
	<button @click="add(2)">+2</button>
   </template>
   //传递参数时,可以采用更易读的方式传递
	store.commit({type: 'add',num: 2})

在 Vuex 中,mutation 都是同步事务

Action

类似于mutation,不同之处在于

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

定义

  actions: {
    async_add(context,n){
      setTimeout(() => {
        context.commit('add',2) //这里我们可以使用仓库中的mutation中的方法并且可以是异步的!
      }, 2000); //Action中使用异步事件
    }
  },

使用
方法一:传统用法

<template>
{{num}}
<button @click="async_add(2)">+2</button>
</template>
methods:{
	async_add(n){
      this.$store.dispatch('async_add',n)
    } //传统写法
 }

方法二:辅助函数

<template>
{{num}}
<button @click="async_add(2)">+2</button>  //异步。两秒钟之后加2
</template>
import {mapActions}  from  'vuex'
methods:{
	...mapActions(['async_add']) //辅助函数
 }

module

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。
对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象。
对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState

在store文件夹中新建module子文件夹作为子模块,在module模块中新建home.js作为子仓库home.

命名空间

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

通过添加 namespaced: true 的方式使子模块成为带命名空间的模块。
当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。

当分模块后,取值方式可以适当改变,以方便我们取值:

子仓库 store/module/home.js

export default{
    namespaced:true,//开启命名空间
    state(){
        return{
            name:'home'
        }
    }
}

主仓库 store/index.js

import { createStore } from 'vuex'
import home from './modules/home'  //将子仓库引入总仓库
export default createStore({
  state: {
    name:app,
    msg:'is store',
    num:0
  },
 })

组件中使用 Home.vue

<template>
  {{msg}}
  {{num}}
  {{name}}
</template>
<script>
import {mapState} from 'vuex'
export default{
 computed:{
 	...mapState('home',['name']), //home仓库里的name,显示为home
 	...mapState(['name']);默认为主仓库的name值,为app ;下面的会 覆盖上面的,此时显示在页面中的name值为app
 	...mapState(['msg','num']), //主要主仓库中有msg和num,直接显示
 	...mapState({
 		 home_name: (state)=>{state.home.name}, //读取的是home仓库中的name值,为home
 		 name:(state)=>{state.name} //读取的是主仓库中的name值,为app
 		 //将不同仓库里的name进行重命名,使name名不同
  }),
 }
上一篇:快捷键


下一篇:codeforces A. Puzzles 解题报告