什么是Vuex?
首先Vuex
是Vue
'全家桶'的成员之一,也是一个专为Vue.js
应用程序开发的状态管理模式。
官方说法: 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
为什么要用Vuex?
因为组件之间是相互独立的,组件之间想要通信。其中有通过props
选项通信,但这只限于父子组件通信,远远不能满足组件之间通信的需求,特别是做中大型的项目。所以就把组件之间需要共享的数据给单独'弄'出来。
通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
什么情况应该用Vuex?
Vuex可以帮助我们管理共享状态,并附带了更多的概念和框架,这需要对短期和长期效益进行权衡。
如果不是开发中大型单页应用,使用Vuex可能是繁琐冗余的,不建议使用。
Vuex的特性
每一个 Vuex
应用的核心就是 store
(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
Vuex 的核心概念
state
: 把组件需要通信的数据定义在store
的state
中。容器的状态(响应式数据,可以触发视图更新的数据)。
举例:
//如果在模块化构建系统中,请确保在开头调用了 Vue.use(Vuex)
//视图状态仓库中(超大的ViewModel,把需要跨组件通信的数据都放到这里)
const store = new Vuex.Store({
//容器状态(响应式数据,可以触发视图更新的数据)
state: {
count: 0
},)
//在组件中通过计算属性来获取 store.state中的成员
Vue.component('component-b', {
template: `
<div>
componentB
<h1>{{count }}</h1>
</div>
`,
created () {
},
data () {
return {
}
},
computed: { //使用computed 来监视count的变化,当count的值一变化,就会调用computed的事件
count () {
return store.state.count
}
}
})
getter
: 就像计算属性一样,getter
的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
举例:
const store = new Vuex.Store({
state: {
todos: [
{ name: '小张',compoleted: true},
{ name: '小李',compoleted: false }
]
},
getters: {
compoletedTodos: state => { //getter 接受state作为其第一个参数
return state.todos.filter (todo => toto.compoleted)
},
comTodosLength: ( state, getters) => { //getter 也可以接受其他的getter作为第二个参数
return getters.compoletedTodos.length
}
}
})
通过属性访问
store.getters.compoletedTodos
mutation
: 它是更改Vuex
的store
中的状态的唯一方法,非常类似于事件,每个mutation
都有一个字符串的事件类型type
和一个回调函数handle
。
举例:
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 变更状态
state.count++
}
}
})
在组件中通过store.commit方法来触发mutation
store.commit('increment ')
通过store.commit
传入额外的参数,即mutation
的载荷(payload
):
举例:
方式一:
mutations: {
increment (state,n) {
state.count += n
}
}
store.commit('increment',10)
方式二: 载荷应该是一个对象
mutations: {
increment (state,payload) {
state.count += payload.amount
}
}
store.commit('increment',{
amount: 10
})
方式三:对象风格的提交方式,但是定义mutation函数保持不变
store.commit({
type:'increment',
amunt: 10
})
action
: action
类似于 mutation
,但是不同的是:
-
action
提交的是mutation
,而不是直接变更状态。 -
action
可以包含任何异步操作
举例:
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
//action 函数接受一个与store实例具有相同方法和属性的context对象
increment (context) {
context.commit('increment')
}
}
})
action
通过 store.dispatch
触发:
store.dispatch('increment')
action
与mutation
最大的不同是:mutation
必须同步执行,而action
就不受约束,可以在action
内部执行异步操作:
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
action
支持同样的载荷方式和对象方式进行分发。
module
: 当项目非常大的时候,应用的所有状态会集中到一个比较大的对象,store
对象就有可能变得相当臃肿。
为了解决以上问题,我们可以将store
分割成模块,同时每个模块拥有自己的state
,mutation
,action
,getter
,还能嵌套子模块,从上至下进行同样方式的分割。
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
辅助函数
-
mapState
辅助函数 -
mapGetters
辅助函数 -
mapMutations
辅助函数 -
mapActions
辅助函数