# vuex
## 介绍
专为 Vue.js 应用程序开发的**状态管理模式**, 采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.
https://vuex.vuejs.org/zh/

1. 修改state状态必须通过 **`mutations`**
2. **`mutations`** 只能执行**同步**代码,类似 ajax、定时器之类的代码不能在mutations中执行
3. 执行**异步**代码,要通过 **`actions`** ,然后将数据提交给 `mutations` 才可以完成
4. state 的状态即共享数据可以在组件中引用
5. 组件中可以调用 action / mutations
## 使用场景
不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。如果您的应用够简单,您最好不要使用 Vuex
## 下载 安装
```bash
npm install vuex --save
```
```js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(vuex)
const store = new Vuex.Store({})
new Vue({
el: '#app',
store
})
```
==Vuex有五个最重要的构造器: state, mutations, actions, getters, modules==
## state
> state是放置所有公共状态的属性,如果你有一个公共状态数据 , 你只需要定义在 state对象中
几种使用方法:
### 原始调用
组件中可以使用 **this.$store** 获取到vuex中的store对象实例
```html
state的数据:{{ $store.state.count }}
```
### 结合计算属性
将state属性定义在计算属性中
```js
computed: {
count () {
return this.$store.state.count
}
}
```
### 辅助函数 mapState
> 方便获取多个状态, 像前面在 computed 里多次定义太啰嗦
```js
// 第一步:导入mapState
import { mapState } from 'vuex'
// 第二步:采用数组形式引入state属性
// 第三步:mapState函数返回的是对象, 利用展开运算符合并到计算属性里
computed: {
...mapState([
'count',
'count2',
//...
])
}
// 如果计算属性的名称和state的子节点名称不同
computed: {
...mapState({coutAlias: state => state.cout}),
}
// 使用
state的数据:{{ count }}
```
## getters
> 除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到 getters
> 可以认为是 store 的计算属性
例如,state中定义了list,为1-10的数组,组件中,需要显示所有大于5的数据
```js
state: {
list: [1,2,3,4,5,6,7,8,9,10]
},
getters: {
// getters函数的第一个参数是 state
// 必须要有返回值
filterList: state => state.list.filter(item => item > 5)
}
```
===通过属性访问时会进行缓存===
getter 可以返回一个函数, 实现向 getter 传参
```js
state: {
list: [1,2,3,4,5,6,7,8,9,10]
},
getters: {
// getters函数的第一个参数是 state
// 必须要有返回值
filterList: state => (n)=>state.list.filter(item => item > n)
}
```
===通过函数每次都进行调用不会缓存===
### 原始调用
```vue
{{ $store.getters.filterList }}
```
```vue
{{ $store.getters.filterList(5) }}
```
### 结合 computed
```js
computed: {
filterList () {
return this.$store.getters.filterList
}
}
```
### 辅助函数 mapGetters
```js
computed: {
...mapGetters(['filterList'])
}
// 重命名
computed: {
...mapGetters({filterListAlias:'filterList'})
}
// ...
{{ filterList }}
```
## mutations
> state数据的修改只能通过mutations,并且mutations必须是同步更新, 不能写异步代码 (比如axios)
mutations是一个对象,对象中存放修改state的方法
```js
mutations: {
// 方法里参数 第一个参数是当前store的state属性
// 第二个可选参数payload, 载荷 运输参数, 外部调用mutaiions的时候可以传递参数
addCount (state, data) {
state.count += data
}
},
```
### this.$store.commit
```js
// 调用方法
//...
//...
methods: {
addCount(num){
this.$store.commit('addCount', num) // commit 提交
}
}
```
### mapMutations
> mapMutations和mapState很像,它把位于mutations中的方法提取了出来,我们可以将它导入
```js
import { mapMutations } from 'vuex'
methods: {
...mapMutations(['addCount']),
}
// 对像写法, 重命名
methods: {
...mapMutations({changeAllDistrictAlias:'changeAllDistrict'})
}
```
## actions
> state是存放数据的,mutations是同步更新数据,actions则负责进行异步操作(比如请求, 定时器)
```js
// 定义actions
actions: {
// 第一个参数context表示当前的store的实例,可以通过 context.state 获取状态,也可以通过context.commit 来提交mutations,也可以 context.dispatch调用其他的action
// 第二个参数data 可选
getAsyncCount (context) { // 这里可以用解构 getAsyncCount({ commit })
setTimeout(function(){
context.commit('addCount', 123) // 对应的可以简写 commit('addCount', 123)
}, 1000)
},
// 写法2
getAsyncCount ({commit}) {
setTimeout(function(){
commit('addCount', 123)
}, 1000)
},
}
```
### 原始调用
```js
addAsyncCount () {
this.$store.dispatch('getAsyncCount') // dispatch 委派
}
```
```js
// 传参
addAsyncCount () {
this.$store.dispatch('getAsyncCount', 123)
}
```
### mapActions
> actions也有辅助函数,可以将action导入到组件中
```js
import { mapActions } from 'vuex'
methods: {
...mapActions(['getAsyncCount'])
}
// 重命名
methods: {
...mapActions({ initialDistrictAlias: 'initialDistrict' })
}
```
直接通过 this.方法就可以调用
```vue
```
## Module
> 每个子模块都是一个对象, 可以自己拥有state, mutations, actions, getters
```js
const store = new Vuex.Store({
modules: {
user: {
state: {
token: '12345'
}
},
setting: {
state: {
name: 'Vuex实例'
}
}
})
```
### 原始调用
```vue
// store.state.模块名.字段名
用户token {{ $store.state.user.token }}
网站名称 {{ $store.state.setting.name }}
```
### 配合 getters + mapGetters
```js
// 配合getters简写
getters: {
token: state => state.user.token,
name: state => state.setting.name
}
// 再配合mapGetters
computed: {
...mapGetters(['token', 'name'])
}
```
### 命名空间
==注意: 默认情况下,模块内部的 action、mutation 和 getter 是注册在**全局命名空间**的==(简单的说不加模块名直接带上字段名就可以调用 state.token) , 为了保证内部模块的高封闭性,采用namespaced来进行设置
```js
user: {
namespaced: true, // 命名空间
state: {
token: '12345'
},
mutations: {
// 这里的state表示的是user的state
updateToken (state) {
state.token = 678910
}
}
},
```
方案1:**带上模块的属性名路径**
```js
// 对于有命名空间的action和mutation, 要带上 '命名空间/模块名'
methods: {
...mapMutations(['user/updateToken']),
test () {
this['user/updateToken']()
}
}
```
```js
// 调用模块里的mutatios/actions
this.$store.dispatch('user/getUserInfo')
this.$store.commit('user/getUserInfo')
```
```js
computed: {
// 把模块名字符串当成第一个参数传进去
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions('some/nested/module', [
'foo',
'bar'
])
}
```
方案2: **createNamespacedHelpers** 创建基于某个命名空间辅助函数
```js
import { mapGetters, createNamespacedHelpers } from 'vuex'
// ...
const { mapMutations: mapMutationsUser } = createNamespacedHelpers('user') //创建出属于当前模块的辅助函数, 是一个对象, 里面包括mapGetters, mapState, mapMutations
// 解构并重命名
export default {
computed: {
...mapGetters(['token', 'appName']) // 这里就是子模块里的
},
methods: {
...mapMutationsUser(['setUserInfo'])
}
}
```
## 持久化
`VuexPersistence`
https://www.npmjs.com/package/vuex-persist
https://www.cnblogs.com/lemoncool/p/9645587.html
### Steps
Import it
```
import VuexPersistence from 'vuex-persist'
```
> NOTE: In browsers, you can directly use `window.VuexPersistence`
Create an object
```js
const vuexLocal = new VuexPersistence({
storage: window.localStorage
})
```
Use it as Vue plugin.
```js
const store = {
state: { ... },
mutations: { ... },
actions: { ... },
plugins: [vuexLocal.plugin]
}
```
vuex-persist 的详细属性:
| 属性 | 类型 | 描述 |
| ------------ | ---------------------------------- | ------------------------------------------------------------ |
| key | string | 将状态存储在存储中的键。默认: 'vuex' |
| storage | Storage (Web API) | 可传localStorage, sessionStorage, localforage 或者你自定义的存储对象. 接口必须要有get和set. **默认是: window.localStorage** |
| saveState | function (key, state[, storage]) | 如果不使用存储,这个自定义函数将保存状态保存为持久性。 |
| restoreState | function (key[, storage]) => state | 如果不使用存储,这个自定义函数处理从存储中检索状态 |
| reducer | function (state) => object | 将状态减少到只需要保存的值。默认情况下,保存整个状态。 |
| filter | function (mutation) => boolean | 突变筛选。看mutation.type并返回true,只有那些你想坚持写被触发。所有突变的默认返回值为true。 |
| modules | string[] | 要持久化的模块列表。 |
## 总结
* state 仓库状态对象
* mutations 改变数据的函数, 同步
* action 异步函数
* getters 类似计算属性的数据获取
* modules 子模块