谈谈对vuex的理解
首先我们先抛出三个问题
(1)有了vuex我们是不是就不需要组件之间传参?
(2)vuex和localstorage啥区别?
(3)vuex里面直接修改state为什么还要有专门的修改方法mutation?
先把3个问题的答案放出来:
(1)vuex是多个组件,共享同一个数据的状态管理工具。只是父子之间的数据传递没必要使用vuex,小型项目官方都不推荐使用vuex,只会增加项目的负担,大型的项目并且是多个组件共享的用vuex更好
(2)vuex和localstorage两者应用场景不同。vuex是当前vue项目的全局状态对象,存放在内存中,一旦当前vue项目刷新,vuex的数据也将恢复默认值;而localstorage是存放在浏览器中的对象,即使刷新数据也仍然存在。
(3)对于这个问题,在创建 store 的时候传入 strict: true, 开启严格模式,那么任何修改state的操作,只要不经过mutation的函数,vue就会 throw error
const store = new Vuex.Store({
state,
strict:true
//开启严格模式后,只能通过mutation来改变状态(不支持异步)否则会报错
})
//下面的开启严格模式就会报错,不开启是可行的
console.log(store.state.count) //0
store.state.count = 3;
console.log(store.state.count) //3
注意:发布环境下不要开启严格模式,严格模式会深度监测状态树来检测不合规的状态变化,造成不必要的性能损失
但是真正原因是:
Vuex的state是响应式的,响应式就是状态改变页面组件也实时更新。但是要实现响应式必须通过提交mutation去改变state,并且还需要遵守一定的规则
下面从是什么,为什么,怎么用的角度来谈对vuex的理解
【1】vuex是什么
多个组件,共享,同一个数据的状态管理工具
vuex适用于大型单页应用,简单的应用使用 Vuex 可能是繁琐冗余的
【2】为什么
当在开发大型单页应用时,会出现多个视图组件依赖同一个状态,来自不同视图的行为需要变更同一个状态。如登录状态、加入购物车、音乐播放等。
或许你认为可以用传参的方法解决组件之间互相传值的问题。但是传参的方法对于多层嵌套的组件将会变得很繁琐,并且对于兄弟组件间的传递无能为力。所以vuex出现了,相当于一个“前端的数据库”。
Vuex主要用于解决组件之间同一状态的共享问题,它能把组件的共享状态抽取出来,当做一个全局单例模式进行管理。 这样不管你在何处改变状态,都会通知使用该状态的组件做出相应修改。即Vuex采用集中式存储管理应用的所有组件的状态 这里的关键在于集中式存储管理。 这意味着本来需要共享状态的更新是需要组件之间的通讯,而现在有了Vuex,组件就都和store通讯了
【3】怎么用
安装使用步骤
1.安装
sudo cnpm install vuex -S
2.引入状态管理工具vuex
import vuex from 'vuex'
import store from './vuex/store'
3.main.js里面实例化
new Vue({
el: '#app',
router, :style="{ 'left': leftnum + 'px' }"
store,
components: { App },
template: '<App/>'
})
4.在src里面和views同级创建vuex文件里面store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
// 定义状态
state: {
//动态路由的数组
keepAlive:[],
//全局域名
domainName:"",
}
})
export default store
5.使用:this.$store.state.名字
使用方法核心内容
(1)state 存放状态
(2)mutations 美[mjuːˈtion] 同步的,唯一更改state的方法是提交 mutation。
(3)getters 加工state成员给外界类似于计算属性
(4)actions 异步的,然后提交mutation去操作state
(5)modules 模块化状态管理
image.png
(1)state 存放状态
const store = new Vuex.store({
state:{
name:'jack'
},
})
//页面调用
this.$store.state
(2)mutations同步的对state操作的集合,比如对该数据的修改、增加、删除等等。里面的函数有两个默认形参([state] [payload])
state是当前VueX对象中的state
payload是该方法在被调用时传递参数使用的
//index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.store({
state:{
name:'jack'
},
mutations:{
//es6语法,等同edit:funcion(){...}
//编辑
edit(state,payload){
//(1)直接调用
state.name = 'wayne'
//(2)传值调用
state.name = payload
//(3)传值对象调用
state.name = payload.name
},
//新增
myadd(state,payload){
//新增逻辑
Vue.set(state,"name1","dawei")
},
//删除
mydel(state,payload){
//删除逻辑
Vue.delete(state,"name1")
},
}
})
export default store
//页面通过this.$store.commit调用
//(1)直接调用
this.$store.commit('edit')
//(2)传值调用
this.$store.commit('edit','wayne')
//(3)传值对象调用
this.$store.commit('edit',{name:'wayne',sex:'男'})
//还可以这么写
this.$store.commit({
type:'edit',
payload:{
name:'wayne',
sex:'男'
}
})
image.png
新增和删除不能使用xx.xx = xx,delete state.info.age这种原来的模式因为不是响应式的,响应式规定新增和删除有自己的方法,这样才能自动更新到组件上面去;
新增用Vue.set(state,"name1","dawei"),
删除用Vue.delete(state,"name1")
(3)getters 加工state成员给外界类似于计算属性
可以对state中的成员加工后传递给外界,Getters中的方法有两个默认参数
state 当前VueX对象中的状态对象
getters 当前getters对象
//index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.store({
state:{
name:'jack',
age:'15'
},
mutations:{
//编辑
edit(state,payload){
}
},
getters:{
nameInfo(state){
return "姓名:"+state.name
},
fullInfo(state,getters){
return getters.nameInfo+'年龄:'+state.age
}
}
})
export default store
// 调用
this.$store.getters.fullInfo//姓名:jack 年龄:15
(4)actions 专门放置异步操作,然后提交mutation去操作state
注意:Action 提交的是 mutation,而不是直接改变state,只有mutation能改变state。
至于是在页面组件中等异步操作(如axious请求接口改变state)完成后去commit调用mutation;还是直接action去做异步axious,根据不同的业务场景有不同的选择,也有不同的好处体现出来。
比如多次遇到的异步(如axious请求接口改变state)那就直接放在action里面,需要的时候页面组件直接使用this.$store.dispatch就可以不用重复写axious,所以vuex只是为了更灵活使开发者多一个选择,让代码尽可能的变动优雅。
Actions中的方法有两个默认参数
context 上下文(相当于箭头函数中的this)对象
payload 挂载参数
//index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.store({
state:{
name:'jack'
},
mutations:{
//es6语法,等同edit:funcion(){...}
//编辑
edit(state,payload){
//(2)传值调用
state.name = payload
}
},
actions:{
Edit(context,payload){
//异步操作
setTimeout(()=>{
//提交mutations方法,修改state
context.commit('edit',payload)
},2000)
}
}
})
export default store
//在页面组件中调用:
this.$store.dispatch('Edit','wayne')
(5)modules 模块化状态管理
当项目庞大,状态非常多时,可以采用模块化管理模式。Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。
const store = new Vuex.Store({
models:{
a:{
state:{},
getters:{},
....
},
b:{
state:{},
getters:{},
....
},
}
})
//调用
this.$store.state.a
//而提交或者dispatch某个方法和以前一样,会自动执行所有模块内的对应type的方法:
this.$store.commit('editKey')
this.$store.dispatch('aEditKey')