Vuex 是什么?
是一个集中式存储组件数据的仓库
npm安装
npm install vuex --save
vuex使用
在一个模块化的打包系统中,必须显式地通过 Vue.use()
来安装 Vuex:
store的index.js文件中:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
注意
上述步骤必须在创建仓库之前完成!!!
vuex核心概念(store&&state)
仓库
每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,
它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:
- Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,
若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。 - 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地
提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,
从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
vuex仓库环境的搭建
//state会转绑给store对象
//任意一个组件内都可以通过$store来访问仓库对象
import vue from "vue";
import vuex from "vuex";
vue.use(vuex)
const store = new vuex.Store({
state:{count:0}
})//新建仓库
new vue({
store,
})//注册仓库
访问仓库数据
由于上一步把 store 的实例注入了所有的子组件 所以任何组件都可以通过其自身的$store来访问仓库
<template>
<div>
{{count}}
</div>
</template>
<script type="text/ecmascript-6">
export default {
name: "App",
data(){
return {
count:this.$store.state.count
}
}
}
</script>
创建计数器组件
在整个组价的改造过程中,我们发现是需要修改计数器的值,
当我们通过 `this.$store.state.count++` 这种方式去修改store中的数据时发现仓库数据变了
可是界面上的数据没有更新. 在对仓库数据进行修改时 我们必须遵守 Vue 的响应规则
所以仓库中的所有数据在使用时最好都定义成计算属性
👆自己的理解:进行了这步操作: count:this.$store.state.count ,通过深拷贝将
仓库中的数据转存了一份,仓库中的数据一般都是共享数据,这样一来便成了独立
的数据,自然不会渲染到界面中。不建议使用转存的形式来读取仓库中的数据
而是应该使用计算属性来读取仓库中的数据;这样还可以避免脏数据的问题;
也不会丢失数据的响应式能力
仓库中的数据在组件上都有一个计算属性与之对应
严格模式
开启严格模式,仅需在创建 store 的时候传入 strict: true
:
const store = new Vuex.Store({
// ...
strict: true
})
在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。
这能保证所有的状态变更都能被调试工具跟踪到。
严格模式下,组件中直接修改了仓库中的数据,页面仍然可以渲染,但会报错!!
👆由此引入Mutation
Mutation
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
Vuex 中的 mutation 非常类似于事件:
每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。
这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
mutations:{
事件名(state){
数据的操作
}
}
注册Mutation
//改造仓库文件
import Vuex from "vuex"
import Vue from "vue"
Vue.use(Vuex)
const store = new Vuex.Store({
strict: true,
state:{
count:0
},
mutations:{
inc(state){
state.count++
},
dec(state){
state.count--
}
}
})
export default store
使用mutation
你不能直接调用一个 mutation handler。
这个选项更像是事件注册:“当触发一个类型为 increment
的 mutation 时,调用此函数。”
要唤醒一个 mutation handler,你需要以相应的 type 调用 store.commit 方法:
store.commit('事件名')//提交mutation来修改仓库中的数据
提交载荷(Payload)
你可以向 store.commit
传入额外的参数,即 mutation 的 载荷(payload):
// ...
mutations: {
//当n等于一个值时,就代表默认值,也就是没传值的时候会有一个默认值
inc (state, n) {
state.count += n
}
}
store.commit('inc', 10)
在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读:
也就是说,当要传递多个数据的时候,载荷应该写成对象的形式
如:{test,mount}
// ...
mutations: {
inc (state, obj) {
state.count += obj.amount
}
}
store.commit('inc', {
amount: 10
})
补充:
当提交mutation时没有传递载荷时
在注册mutation的时候解构赋值使其为空对象
mutations:{
add(state,{step=1,msg}={}){
state.count+=step
}
}
this.$store.commit("add")
对象风格的提交方式
提交 mutation 的另一种方式是直接使用包含 type
属性的对象:
store.commit({
type: 'inc',
amount: 10
})
当使用对象风格的提交方式,整个对象都作为载荷传给 mutation 函数,因此 handler 保持不变:
mutations: {
inc (state, obj) {
state.count += obj.amount
}
}
Mutation 需遵守 Vue 的响应规则
既然 Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。
这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项:
-
最好提前在你的 store 中初始化好所有所需属性。
-
当需要在对象上添加新属性时,你应该
使用 Vue.set(obj, ‘newProp’, 123)
Mutation 必须是同步函数
vue 的 devtool 中会记录每一条 mutation 日志。如果mutation中存在异步代码,会导致devtools中的记录变的混乱不可维护
当我们在mutation中书写异步代码时,严格模式下vue会提出警告,非严格模式下vue不会做出任何反应
由此引入Action
什么是Action
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
使用
让我们来注册一个简单的 action:
actions:{
事件名(store,参数){
setTimeout(()=>{
store.commit(“事件名”,参数)
},2000)
}
}
传参规范与上面mutation一样
import Vuex from "vuex"
import Vue from "vue"
Vue.use(Vuex)
const store = new Vuex.Store({
// strict: true,
state:{
count:0
},
getters:{
flag(state){
return state.count%2==0?"偶数":"奇数"
}
},
mutations:{
inc(state,obj){
state.count+=obj.amount
},
dec(state){
state.count--
},
asyncInc(state){
state.count++
}
},
actions:{
asyncInc(store){
setTimeout(()=>{
store.commit("asyncInc")
},2000)
}
}
})
export default store
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit
提交一个 mutation,或者通过 context.state
和 context.getters
来获取 state 和 getters。当我们在之后介绍到 Modules 时,你就知道 context 对象为什么不是 store 实例本身了。
actions: {
increment ({ commit }) {
commit('increment')
}
}
分发 Action
Actions 支持同样的载荷方式和对象方式进行分发:
// 以载荷形式分发
store.dispatch('incrementAsync', {
amount: 10
})
// 以对象形式分发
store.dispatch({
type: 'incrementAsync',
amount: 10
})
//map辅助
methods:{
...mapMutations(["inc","dec"]),
...mapActions(["asyncInc"])
}
如何修改vux仓库中的数据
通过提交一个mutation来同步的!!!修改仓库中的数据
通过分发一个action来异步的提交一个mutation;从而达到异步修改仓库数据的目的
action通过异步的axios拿到后台的数据
Devtools只认识mutation,mutation同步的操作数据
之后数据再相应的渲染页面
Getters
有时候我们需要从 store 中的 state 中派生出一些状态.如果有多个组件需要用到此状态
就可以在 store 中定义“getters”(可以认为是 store 的计算属性)。就像计算属性一样,
getters 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
Getters 接受 state 作为其第一个参数:
// 仓库文件
import Vuex from "vuex"
import Vue from "vue"
Vue.use(Vuex)
const store = new Vuex.Store({
strict: true,
state:{
firstName:"T",
lastName:"mac"
},
//与计算属性computed类似
//但是getters没有对应的get,set方法
getters:{
//👇fullName可以访问仓库里的数据
fullName(state){
//console.log(this) //undefined
return state.firstName +"-"+ state.lastName
}
}
})
export default store
访问Getters
Getters 会暴露为 store.getters
对象,你可以以属性的形式访问这些值
//app.vue
export default {
name: "App",
computed:{
fullName(){
return this.$store.getters.fullName
}
}
}
辅助函数
- 仓库中的数据在组件上都有一个计算属性与之对应
- 仓库中的工具函数(mutation action)在组件上都有一个函数与之对应
import { mapState,mapGetters,mapMutations,mapActions} from ‘vuex’
简化业务组件的开发
- mapState({}) 或者 mapState([])
- mapGetters({}) 或者 mapGetters([])
- mapMutations({}) 或者 mapMutations([])
- mapActions({}) 或者 mapActions([])
一般规律
- vuex中的state 我们在组件中使用时通常需要有对应的computed
- vuex中的getters 我们在组件中使用时通常需要有对应的computed
- vuex中的mutations 我们在组件中使用时通常需要有对应的methods
- vuex中的actions 我们在组件中使用时通常需要有对应的methods
mapState用法
mapState(["count" ]) = {count:fn} = { count(){ return this.$store.state.count } }
...mapState(["count" ]) = count(){ return this.$store.state.count }
computed:{
count(){
return this.$store.state.count
}
}
//当count在另一个组件的别名为myCount,但是这两个是同一个数据,只是名字不一样
mapState({myCount:"count" }) = { myCount(){ return this.$store.state.count } }
...mapState({myCount:"count" }) = myCount(){ return this.$store.state.count }
computed:{
myCount(){
return this.$store.state.count
}
}
mapGetters用法
与mapState用法一致
mapMutations用法
mapMutations(["add"]) = {add:fn} = { add(){ this.$store.commit('add') } }
...mapMutations(["add" ]) = add(){ this.$store.commit('add') }
methods:{
add(){
this.$store.commit('add')
}
}
mapMutations({myAdd:"add" }) = { myAdd(){ this.$store.commit('add') } }
...mapMutations({myAdd:"add" }) = myAdd(){ this.$store.commit('add') }
methods:{
myAdd(){
this.$store.commit('add')
}
}
mapActions用法
与mapMutations用法一致