vue面试题:谈谈你对vuex的理解
面试题:谈谈你对vuex的理解
这是本人的第一篇博客 哈哈哈哈哈哈哈哈写的好或不好 请谅解喔~
当面试官问我们对vuex的理解的时候,我们不能只说“vuex是一个专为vue.js应用程序开发的状态管理模式”,尽量不要让面试官连续追问(总会问到自己不会的然后说你实力还差那么点来可以得降薪),应该从这几个方面一次性去说清楚:
1.为什么要用vuex?
2. 什么是vuex?
3. 怎么用vuex(五大核心属性概念,应用…)
一、为什么要用vuex?
在大型复杂的项目中(多级组件嵌套),需要实现一个组件更改某个数据,多个组件自动获取更改后的数据进行业务逻辑处理,这时候使用vuex比较合适。假如只是多个组件间传递数据,使用vuex未免有点大材小用,其实只用使用组件间常用的通信方法即可 。
那么怎么安装使用vuex呢?
1.首先 安装vuex
cnpm install vuex -save
2. 在src目录下创建store文件夹
3. 在store文件夹内创建index.js文件
4. 在index.js 文件内引入 vue 和注册vuex
import Vue from “vue”
import Vuex from “vuex”
5.对vuex进行实例化 并导出
const store = new Vuex({
核心配置
})
export default store
6. 将store配置到vue实例中
new Vue({
router,
store,
render: h => h(App)
})
二、什么是vuex?
Vuex是专门为Vue服务,用于管理页面的数据状态、提供统一数据操作的生态系统,相当于数据库mongoDB,MySQL等,任何组件都可以存取仓库中的数据。
理解性(可读)
Vuex采用MVC模式中的Model层,规定所有的数据必须通过action—>mutaion—>state这个流程进行来改变状态的。再结合Vue的数据视图双向绑定实现页面的更新。统一页面状态管理,可以让复杂的组件交互变的简单清晰,同时在调试时也可以通过DEVtools去查看状态。
在当前前端的spa模块化项目中不可避免的是某些变量需要在全局范围内引用,此时父子组件的传值,子父组件间的传值,兄弟组件间的传值成了我们需要解决的问题。虽然vue中提供了props(父传子)commit(子传父)兄弟间也可以用localstorage和sessionstorage。但是这种方式在项目开发中带来的问题比他解决的问题(难管理,难维护,代码复杂,安全性低)更多。vuex的诞生也是为了解决这些问题,从而大大提高我们vue项目的开发效率
三、怎么用vuex?
vuex五大核心属性:state,getter,mutation,action,module
- state:存储数据,存储状态;在根实例中注册了store 后,用 this.$store.state 来访问;对应vue里面的data;存放数据方式为响应式,vue组件从store中读取数据,如数据发生变化,组件也会对应的更新。
- getters:可以认为是 store 的计算属性,它的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
- mutation:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
- action:包含任意异步操作,通过提交 mutation 间接更变状态。
- module:将 store 分割成模块,每个模块都具有state、mutation、action、getter、甚至是嵌套子模块。
对于vuex的数据传递流程,如下图所示:
关于state
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
count: 0
}
export default new Vuex.Store({
state
})
我们在store里定义了count,该怎么在组件里去用呢?
<div class="hello">
<h3>{{$store.state.count}}</h3>
</div>
</template>
这时候我们就能在页面中看到
就是这样用state啦~下面是mutations怎么用 其实他就像组件里的methods 能够对state状态进行修改
* mutations 里面放置的是我们操作state对象属性的方法
*/
const mutations = {
mutationsAddCount(state, n = 0) {
return (state.count += n)
},
mutationsReduceCount(state, n = 0) {
return (state.count -= n)
}
}
export default new Vuex.Store({
state,
mutations
})
我们在mutations写了两个修改状态的方法
<div class="hello">
<h3>{{$store.state.count}}</h3>
<div>
<button @click="handleAddClick(10)">增加</button>
<button @click="handleReduceClick(10)">减少</button>
</div>
</div>
</template>
handleAddClick(n){
this.$store.commit('mutationsAddCount',n);
},
handleReduceClick(n){
this.$store.commit('mutationsReduceCount',n);
}
}
相信这样大家就能看懂mutations在组件中怎么使用了吧~
让我们看一下效果⑧
下面是actions的使用
actionsAddCount(context, n = 0) {
console.log(context)
return context.commit('mutationsAddCount', n)
},
actionsReduceCount({ commit }, n = 0) {
return commit('mutationsReduceCount', n)
}
}
export default new Vuex.Store({
state,
mutations,
actions
})
这里我在两个方法中使用了两个不同的参数,一个是context,它是一个和store对象具有相同对象属性的参数。在第二个函数中,我是直接使用了这个对象的commit的方法。
<div>
<button @click="handleActionsAdd(10)">异步增加</button>
<button @click="handleActionsReduce(10)">异步减少</button>
</div>
this.$store.dispatch('actionsAddCount',n)
},
handleActionsReduce(n){
this.$store.dispatch('actionsReduceCount',n)
}
actions和mutations操作效果一样的 只不过actions是异步操作 为啥是异步呢?因为actions不能直接修改state 需要通过调用mutations里的方法来执行操作 然后我们在组件内通过this.$store.dispatch(“方法名”,要传的值)
然后就剩getters啦! 他的作用跟组件里的computed类似 下面就来使用一下吧
getterCount(state) {
return state.count
}
}
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
在组件内通过 this.$store.getter.getterCount 来使用就可以啦~
最后是 modules 它可以使store变得模块化
之前的项目都是
* mutations 里面放置的是我们操作state对象属性的方法
*/
const mutations = {
mutationsAddCount(state, n = 0) {
return (state.count += n)
},
mutationsReduceCount(state, n = 0) {
return (state.count -= n)
}
}
export default new Vuex.Store({
state,
mutations
})
都是根级别的state mutations getters 这些 这种单一的状态树,应用的所有状态都会集中在一个比较大的对象上面,随着项目需求的不断增加,状态树也会变得越来越臃肿,增加了状态树维护的复杂度,而且代码变得沉长;因此我们需要modules来为我们的状态树分隔成不同的模块,每个模块拥有自己的state,getters,mutations,actions;而且允许每个module里面嵌套子module;如下:
state: { ... },//局部state
mutations: { ... },
actions: { ... },
getters: { ... }
}
*const moduleB = {
state: { ... },//局部state
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({state:{ ... },//全局state
modules: {
a: moduleA,
b: moduleB
}
})
需要注意的
- Vuex在组件中computed中使用的时候,计算属性不能和state的数据项同名(同名了也不会报错,就是获取不了数据了)
- 默认情况下,没有设置命名空间的时候,模块内部的 action、mutation 和 getter 是(除了state)注册在全局命名空间的(如果有重名就会报错 [vuex] duplicate getter key: [method])——这样使得多个模块能够对同一 mutation 或 action 作出响应。
解决方法是加命名空间 namespaced: true
在modules内的每个模块加入命名空间
注册到组件中
computed: {
...mapState('module1', {
width: state => state.width, // 关联, 此处的state 为 module1/state
height: state => state.height
})
},
methods: {
...mapMutations('module1', { // 命名空间module1
widthAdd: 'WIDTH_ADD', // 通过mutation-types.js
addHeight: 'addHeight' // 直接加在mutations上面的方法
}),
}
3.注册完成,使用
this.widthAdd() // 将 `this.widthAdd()` 映射为 `this.$store.commit('module1/widthadd')`
console.log(this.width) // this.width已经变为commit以后的值
划分模块的好处
state更为容易管理,尤其在团队人数多的时候,自己负责自己的state,既保证store了完整的状态树,又避免了相互之间的state冲突
不管是命名,或是操作 state 都会变得更加扁平和直观
到此为止vuex就没啥压力咯
但是vuex官方给了我们一个更简单的方式来使用vuex, 也就是 {mapState, mapMutations, mapActions, mapGetters} 通过这几个辅助函数 来使用store中的state mutations actions getters等
如有错误 请各位大神多多指教喔~
我们下期博客见!
上一篇: Rxjava基本原理解析(四)
下一篇: 关于JAVA8的 Stream学习