Vuex状态管理工具
vuex是什么?
vuex是一个专门为vue.js应用程序开发的状态管理模式,采用集中式存储管理应用的所有组件的状态,解决多组件间数据通信。
使用vuex的好处:
- 数据的存取一步到位,不需要层层传递
- 数据的流动非常清晰
- 存储在Vuex中的数据都是响应式的
什么样的数据适合存储到vuex中?
需要共享的数据。
vuex的作用:频繁、大范围的数据共享。
vue官方提供的独立于组件体系之外的,管理公共数据的工具。
配置
如果采用脚手架方式进行创建,无需任何操作,可以忽略此步骤。
新建store文件->index.js,进行如下配置,在mian.js中进行引入
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export defult new Vuex.store({
// 数据,相当于data
state: {
},
getters: {
},
// 里面定义方法,操作state方法
mutations: {
// 每一项都是一个函数,可以声明两个形参
mutation名1(state[,载荷]) {
},
mutation名2(state[,载荷]) {
},
},
// 操作异步操作mutation
actions: {
},
modules: {
},
})
mian.js中
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
Vuex 五个概念
vuex分为五个大块:
- state:统一定义公共数据(类似于data)
- mutations:使用它来修改数据(类似于methods)
- getters:类似于computed(计算属性,对现有的状态进行计算的到新的数据)
- actions:发起异步请求
- modules:模块拆分
在项目中安装和配置Vuex
整体步骤:
- 安装
- 配置
-
- 创建Vuex.store实例
- 向Vue实例注入store
- 使用。在组建中使用store
步骤说明:
-
安装包
进入项目目录,安装包
-
实例化store
与router一样,当我们在项目中使用Vuex之后,为了方便代码维护,我们一般需要做特殊的目录调整,约定的结构如下。
根组件
└── src
├── main.js
├── router
│ └── index.js # 路由
└── store
└── index.js # vuex
在store/index.js中放置具体的代码如下:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state() {
return {
// 就是公共的数据,所有的组件都可以使用
count: 100
}
}
})
export default store
- 向Vue实例注入store
在src/main.js中:导入store,并注入Vue实例
// 1. 导入store
import store from './store'
new Vue({
store // 注入vue实例
})
-
在组件中使用store
在任意组件中,通过this.$store.state来获取公共数据。
Vuex-state定义公共数据并在组件中使用
概念:State 本质上就是Object 对象
state 的作用是:保存公共数据(多组件中共用的数据)
state 是响应式的:如果修改了数据,相应的在试图上的值也会变化。
组件访问state 数据的第一种方式
在每个Vue组件中,可以通过
this.$store.state.全局数据名称访问store中的数据
定义公共数据格式
new Vuex.store({
state() {
return 属性名:属性值
}
})
使用公共数据:
在组件中,通过this.$store.state.属性名 来访问。
在模板中,可以省略this而直接写成: {{ $store.state.属性名 }}
组件访问state数据的第二种方式
import { mapState } from 'vuex'
export default {
name: 'left',
computed: {
...mapState(['count']),
},
}
小结:
-
直接使用:this.$store.state.XXX
-
map辅助函数:
computed: { ...mapState(['XXX']), ...mapState({'新名字':'XXX'}) }
Vuex用mutations修改公共数据
Mutation 本质上是javascript函数,专门用来更新Store中的数据。
特点: 想要修改State中的数据,只能调用mutation方法,它是vuex中用来修改公共数据的唯一入口。
好处:能够确保修改来源的唯一性,方便调试和后期维护。
在定义时:它的第一个参数是state,第二个参数是载荷。
在调用时:用this.$store.commit('mutation名', 载荷)来调用
注意:Mutation必须是同步函数,Mutation里面不能放异步代码。
**定义格式:**如下
new Vue.store({
state: {
count: 100,
},
mutations: {
// 每一项都是一个函数,可以声明两个形参
addCount(state,num){
state.count =+ state.count + num
},
reduce(state) {
state.count--
},
}
})
每一项都是一个函数,可以声明两个形参:
- 第一个参数是必须的,表示当前的state。在使用时不需要传入;
- 第二个参数是可选的,表示载荷,是可选。在使用的时候要传入;
使用格式:
// this.$store.commit('mutation名',实参)
methods: {
clickAddBtn() {
this.$store.commit('addCount',10)
},
clickReduceBtn() {
this.$store.commit('reduce')
},
}
这里的commit是固定方法。
mapMutations辅助函数
基于Vuex提供的mapMutations辅助函数,可以方便的吧Store中指定的方法,映射为当前组件的methods。
<button @click="clickAddBtn()"></button>
<script>
// 1. 按需导入 mapMutations 辅助函数
import { mapMutations } from 'vuex'
export default {
methods: {
// 从vuex中把clickAddBtn 映射为当前组件的methods方法
...mapMutations(['clickAddBtn'])
},
}
</script>
小结:
-
直接使用: this.$store.commit('mutation名',参数)
-
map辅助函数:
methods: { ...mapMutations(['mutation名']), ...mapMutations({'新名字': 'mutation名'}), }
vuex-mutations拓展理解
-
问: 为啥是store.mutations的名字?
答:Vuex中的非常类似于事件:每个mutation都有一个字符串的事件类型(type)和一个回调函数。这个回调函数就是我们实际进行状态更改的地方,并且它会接受state 作为第一个参数。
-
数据不可以在该组件内部直接修改吗?
答:不能。虽然语法上不报错,也有响应式的特点。但是不推荐。特别是在严格模式下会报错。若将vue创建store的时候传入strict: true,开启严格模式,那么任何修改state的操作,只要不经过mutation的函数,vue就会报错。
-
可以传递多个数据吗?
答:参数只能有一个:下面写法是不对的:
this.$store.commit('setURL',url,host) // host这个参数将无法被接收到如果希望传递复杂的数据,第二个参数可以是对象或者数组,例如:
this.$store.commit('setURL', { url, host })
Vuex-用getters的派生状态
作用: 它是Vuex中的计算属性,当Store数据源发生变化时,Getter 的返回值会自动更新。
访问 Getter 的你第一种方式
定义格式:
new Vuex.store({
getters: {
// state 就是上边定义的公共数据state
getter的名字1(state) {
return 要返回的值
},
}
})
state就是上边定义的公共数据state
使用格式:
在组件中通过: $store.getters.getter的名字 来访问。
访问 getter 的第二种方式
基于 mapGetters 辅助函数,可以把 store 中的 getter 映射为当前组件的计算属性。
map辅助函数:
computed: {
...mapGetters(['XXX']),
...mapGetters({ '新名字': 'xxx' })
}
<p>
完成状态: {{ isDone }}
</p>
<script>
import { mapGetters } from 'vuex'
export defult {
computed: {
...mapGetter(['isDone'])
}
}
</script>
Vuex-actions发异步请求
Action 本质上是JavaScript 函数,专门用来处理 Vuex 中的异步操作。
actions介绍
- actions 是Vuex 的一个配置项
- 作用: 发异步请求获取数据局,调用mutations 来保存数据,将整个ajax 操作封装到 Vuex的内部。
- 要点:
- action内部可以发起异步请求操作
- action 是简洁修改state的:是通过调用mutation 来修改state。
格式
定义格式:
new Vuex.store({
actions: {
// context 对象会自动转入,它与store 实例具有相同的方法和属性
action的名字(context, 载荷) {
// 1. 发异步请求,请求数据
// 2. commit 调用mutation 来修改数据
// 3. context.commit('mutation名', 载荷)
}
}
})
调用格式:
- 直接使用: 在组件中通过 this.$store.dispatch('actions的名字',参数)来调用action。
- 还可以基于 Vuex 提供的 mapActions 辅助函数,可以方便的把 Store 中指定的Action,映射为当前组件的 methods:
map辅助函数:
methods: {
...mapActions(['actions名'],...mapActions({'新名字':'actions名'}))
}
小结:
action一般用来发异步请求,数据回来之后,再去调用mutations来保存数据。
将ajax请求放在 actions 中有两个好处:
- 代码得到了进一步封装。将发ajax和保存数据到vue绑定在一起。
- 逻辑更通顺。如果数据需要保存在vuex的state中,那么从接口处获取数据的操作就定义在Vuex的actions中。
Vuex-用modules来拆分复杂业务
问题导入:
所有的全局数据、方法都集中到了一起,导致Vuex的结构混乱,不利于现阶段的开发和后期的维护。
modules的作用
拆分模板,把复杂的场景按模块来拆开。
export default new Vuex.Store({
// state: 用来保存所有的公共数据
state: {},
getters: {},
mutatios: {},
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的名字了。
结论: 在使用modules时,建议都给加上namespaced!