为什么要用 vuex ?
首先,需要清楚为什么要用 vuex ,当我们的应用遇到 **多个组件共享状态** 时
- 多层级父子组件状态传递会特别繁琐
- 非嵌套父子组件状态传递也会特别繁琐
vuex
Vuex 是一个专为 Vue.js 应用程序开发的 **状态管理模式**,类似 redux
这种状态管理模式包含:
这种模式遵循的是 单向数据流 模式
vuex 的工作流
安装 vuex
npm i vuex
// or
yarn add vuex
引入 vuex
通过 `import` 引入
通过 `import` 方式引入,需要手动安装(手动调用 `Vue.use(Vuex)`)
通过 \<script\> 引入
通过 \<script\> 方式引入,vuex 会自动安装(也就是主动调用 `Vue.use(Vuex)`)
从 Store 开始
`Store` 就是仓库,我们前面提到的 `state` 就存储在 `store` 中,同时提交动作、修改状态的方法也都由 `store` 提供和管理
创建一个 Store
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
let store = new Vuex.Store({
state: {},
getters: {},
mutations: {},
actions: {}
})
必须在 `Vue.use(Vuex)` 之后创建 `store`
核心概念
- state
- getters
- actions
- mutations
state
state 的创建
存储应用状态数据的对象,`state` 的值可以是一个对象,也可以是一个返回对象的函数,类似 vue 中组件的 `data` ,使用函数的方式
返回对象可以避免对象引用导致的副作用问题
通过 `store.state` 访问状态数据
`state` 数据与组件 `data` 一样是被追踪的
在组件中使用 store
问题: `state` 的更新并不会更新视图
解决
用computed(计算属性)
<template>
<div class="home">
<h2>{{title}}</h2>
<div>{{content}}</div>
</div>
</template>
<script>
import store from '@/stores'
export default {
name: 'home',
computed: {
title() {
return store.state.title
},
content() {
return store.state.content
}
}
}
</script>
store 配置
如果每个组件在使用 `store` 的时候都 `import` 会比较繁琐,这个时候,我们通过 vuex 提供的 `store` 选项把 `store` 对象注入
到 vue 的原型上
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from '@/stores'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
配置注入后,我们就可以在组件实例中使用 `this.$store` 来访问 `store` 对象了
使用辅助函数 `mapState`
当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 `mapState`
辅助函数帮助我们生成计算属性,让你少按几次键,通常我们把 `store` 的 `state` 通过 `mapState` 函数映射到组件的 `computed` 上
通过对象方式进行映射
场景:当组件中已有与 `store` 同名的数据名称
使用扩展运算符组合
通过对象扩展运算符,可以把 `mapState` 返回的 `state` 属性与组件已有计算属性进行融合
getters
有时候我们需要从 store 中的 state 中派生出一些状态,类似组件的 `data` 与 `computed`,`store` 也提供了一个 `getters` 对象来处理
派生数据
getters 函数
与组件属性一样,我们是通过定义一个函数的形式来返回派生数据的,` getters` 函数接受两个参数
- 第一个参数:`state` 对象
- 第二个参数:`getters` 对象
通过属性访问
同样的,与组件计算属性一样,默认是通过属性的方式去访问 `getters` 中的数据的,这种方式与组件的计算属性一样,
也是会缓存 结果的
通过方法访问
我们还可以通过闭包函数的形式返回一个函数,来实现给 `getters` 函数传参,需要注意的是这种方式不支持结果缓存
使用辅助函数 `mapGetters`
与 `mapState` 函数类似,通常映射到组件的 `computed` 上
mutations(改变)
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation(类似 redux 中的 action + reducer),Vuex 中的 mutation 非常类似于事件:
每个 mutation 都有一个字符串的 **事件类型 (type)** 和 一个 **回调函数 (handler)**
`mutation` 中的函数不要直接调用
commit(提交)
type
要提交的 `mutation` 回调函数名称
payload
载荷:提交的额外数据,任意格式
mutation 函数
`mutation` 中的函数被 `commit` 执行的时候,接收两个参数
- 第一个参数:`state` 对象
- 第二个参数: `commit` 提交的 `payload`
在 `mutation` 函数中,我们就可以通过 `state` 对象进行状态数据的修改
使用辅助函数 `mapMutations`
`mapMutations` 函数的使用与 `mapState` 和 `mapGetters` 类似,但是其一般是把组件的 `methods` 映射
为 `store` 的 `mutations` 的 `commit` 调用
mutation 函数必须是同步的
`commit` 方法没有返回值
actions
`action` 中的函数与 `mutation` 中的函数类似,但是它主要用来进行异步任务的处理,然后通过提交 `mutation` 来修改 `state`
> 注意:`action` 中的函数不要直接修改 `state`
dispatch派发
`action` 任务需要通过 `dispatch` 方法来提交(派发),与 `commit` 类似
`dispatch` 方法有返回值,且一定返回一个 `promise` 对象
action 函数
`action` 中的函数执行的过程中也接受两个参数
- 第一个参数:`store` 对象
- 第二个参数: `dispatch` 提交的 `payload`
使用辅助函数 `mapActions`
与 `mapMutations` 函数类似,把组件的 `methods` 映射为 `store` 的 `actions` 的 `dispatch` 调用
Module
这个更多的是基于一种代码组织结构上的辅助
https://vuex.vuejs.org/zh/guide/modules.html
https://vuex.vuejs.org/zh/guide/structure.html