状态管理Vuex全解
2019-05-22 本文已影响0人
YM雨蒙
vuexVuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
- Vue Component --> dispatch 触发异步的 Actions
- Actions --> commit 触发同步的 Mutations
- Mutations --> 修改 State 里面的值
- State 修改以后 --> 会触发 Vue Component 视图的渲染
代码示意
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state.js'
import getters from './getters.js'
import mutations from './mutations.js'
import actions from './actions.js'
import user from './module/user'
Vue.use(vuex)
export default new Vuex.Store({ // 创建vuex 实例
// 参数传递
state,
getters,
mutations,
actions,
modules: {
user
}
})
State
根级别的 state
// store/state.js
const state = {
// 数据源, 类似与 data
appName: 'admin'
}
export default state
在模块中定义 state
// store/module/user.js
const state = {
userName: 'yym'
}
const getters = {
// ...
}
const mutations = {
// ...
}
const actions = {
// ...
}
export default {
// namespaced: true 命名空间
state,
mutations,
actions
}
组件中获取 state 的值
<template>
<div>
{{ appName }}
{{ userName }}
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
// 1. mapState 数组
// ... 展开操作符, mapState返回一个对象, 把对象里的属性扁平化
...mapState([
'appName',
]),
// 2. 传入一个对象
...mapState({
appName: state => state.appName,
userName: state => state.user.userName
}),
// 使用
appName () {
return this.$store.state.appName
},
userName () {
return this.$store.state.user.userName
}
}
}
</script>
Getter
类似于组件中的计算属性
根级别的getters
// src/getters.js
const getters = {
// 基于 appName 计算
appNameWithVersion: (state) => {
return state.appName + 'v2.0'
}
}
export default getters
模块里的 getters
const state = {
userName: 'yym'
}
// 可以用于多个组件
const getters = {
firstLetter: state => {
return state.userName.substr(0, 1)
}
}
const mutations = {
}
const actions = {
}
export default {
state,
getters,
mutations,
actions
}
组件中获取 getters 的值
<template>
<div>
{{appNameWithVersion}}
{{firstLetter}}
</div>
</template>
<script>
import { mapState, mapGetters } from 'vuex'
export default {
computed: {
// 1. 传入数组
...mapGetters([
'appNameWithVersion',
'firstLetter'
]),
// 计算属性中
appNameWithVersion () {
return this.$store.getters.appNameWithVersion
}
}
}
</script>
Mutation
更改
Vuex
的store
中的状态的唯一方法是提交mutation
。
根级别的 mutations
import Vue from 'vue'
const mutations = {
/**
* @param {state} 第一个参数 state 同级的 state 对象
* @params {params} 第二个参数, 文档中为载荷, 就是一个参数
* params 1. 可以是一个值 2. 可以是一个对象
*/
SET_APP_NAME (state, params) {
// 1. 值
state.appName = params
// 2. 对象
state.appName = params.appName
},
// 设置一个state 没有的值 version
SET_APP_VERSION (state) {
Vue.set(state, 'appVersion', 'v2.0')
}
}
export default mutations
组件中提交 mutations 的值
<template>
<div>
{{appName}}
<button @click="hanlderChangeAppName">点击</button>
</div>
</template>
<script>
import { mapState, mapGetters, mapMutations } from 'vuex'
export default {
computed: {
appName () {
return this.$store.state.appName
}
},
methods: {
// 使用 mapMutations
...mapMutations([
'SET_APP_NAME'
]),
hanlderChangeAppName () {
// this.appName = '新的值' 错误, 不能直接修改 state 的值
// 1. 值的提交
this.$store.commit('SET_APP_NAME', '新的值') // 第一个参数名称, 第二个为值
// 2. 对象
this.$store.commit({
type: 'SET_APP_NAME',
appName: '新的值'
})
// version
this.$store.commit('SET_APP_VERSION')
// 3. 对应mapMutations
this.SET_APP_NAME('新的值')
}
}
}
</script>
Action
Action 类似于 mutation,不同在于:
-
Action
提交的是mutation
,而不是直接变更状态。 -
Action
可以包含任意异步操作
模拟异步请求
// app.js
export const getAppName = () => {
return new Promise((resolve, reject) => {
const err = null
setTimeout(() => {
if(!err) resolve({ code: 200, info: {appName: '新的值'}})
else reject(err)
})
})
}
根级别的 actions
import { getAppName } from 'app.js'
const actions = {
// 1. promise
updateAppName ({ commit }) {
getAppName().then(res => {
console.log(res)
const { info:{appName} } = res
commoit('SET_APP_NAME', appName)
}).catch(err => {
console.log(err)
})
},
// 2. async await
async updateAppName({ commit }) {
try {
const { info:{appName} } = await getAppName()
commoit('SET_APP_NAME', appName)
} catch(err) {
console.log(err)
}
}
}
export default actions
组件中分发 actions
<template>
<div>
{{appName}}
<button @click="hanlderChangeAppName">点击</button>
<button @click="hanlderChangeUserName">点击</button>
</div>
</template>
<script>
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
export default {
computed: {
appName () {
return this.$store.state.appName
}
},
methods: {
// 使用 mapMutations
...mapMutations([
'SET_APP_NAME'
]),
// 使用 mapActions
...mapActions([
'updateAppName'
]),
hanlderChangeAppName () {
this.updateAppName()
},
hanlderChangeUserName () {
this.$store.dispatch('updateAppName', '123')
}
}
}
</script>