Vuex 核心知识详解
· 阅读需 10 分钟
Vuex 概述
五个核心:state、getter、mutation、action、module
State
基础配置
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex) // Vue 的插件机制
// Vuex.Store 构造器选项
const store = new Vuex.Store({
state: { // 存放状态
"username": "foo",
"age": 18
}
})
export default store
// 页面路径:main.js
import Vue from 'vue'
import App from './App'
import store from './store'
Vue.prototype.$store = store
// 把 store 对象提供给 "store" 选项,这可以把 store 的实例注入所有的子组件
const app = new Vue({
store,
...App
})
app.$mount()
获取 State
1. 通过属性访问
// 页面路径:pages/index/index.vue
<template>
<view>
<text>用户名:{{ username }}</text>
</view>
</template>
<script>
import store from '@/store/index.js' // 需要引入 store
export default {
data() {
return {}
},
computed: {
username() {
return store.state.username
}
}
}
</script>
2. 通过 this.$store 访问
// 页面路径:pages/index/index.vue
<template>
<view>
<text>用户名:{{ username }}</text>
</view>
</template>
<script>
export default {
data() {
return {}
},
computed: {
username() {
return this.$store.state.username
}
}
}
</script>
3. 通过 mapState 辅助函数获取
// 页面路径:pages/index/index.vue
<template>
<view>
<view>用户名:{{ username }}</view>
<view>年龄:{{ age }}</view>
</view>
</template>
<script>
import { mapState } from 'vuex' // 引入 mapState
export default {
data() {
return {}
},
computed: mapState({
// 从 state 中拿到数据,箭头函数可使代码更简练
username: state => state.username,
age: state => state.age
})
}
</script>
// 页面路径:pages/index/index.vue
<template>
<view>
<view>用户名:{{ username }}</view>
<view>年龄:{{ age }}</view>
</view>
</template>
<script>
import { mapState } from 'vuex' // 引入 mapState
export default {
data() {
return {}
},
computed: mapState([
'username', // 映射 this.username 为 store.state.username
'age'
])
}
</script>
// 页面路径:pages/index/index.vue
<template>
<view>
<view>用户名:{{ username }}</view>
<view>年龄:{{ age }}</view>
</view>
</template>
<script>
import { mapState } from 'vuex' // 引入 mapState
export default {
data() {
return {
firstName: "Li"
}
},
computed: {
...mapState({
username: function (state) {
return this.firstName + ' ' + state.username
},
age: state => state.age
})
}
}
</script>
// 页面路径:pages/index/index.vue
<template>
<view>
<view>用户名:{{ username }}</view>
<view>年龄:{{ age }}</view>
</view>
</template>
<script>
import { mapState } from 'vuex' // 引入 mapState
export default {
data() {
return {}
},
computed: {
// 使用对象展开运算符将此对象混入到外部对象中
...mapState({
username: state => state.username,
age: state => state.age
})
}
}
</script>
Getter
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '我是内容一', done: true },
{ id: 2, text: '我是内容二', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
},
doneTodosCount: (state, getters) => {
// state:可以访问数据
// getters:访问其他函数,等同于 store.getters
return getters.doneTodos.length
},
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
})
export default store
获取 Getters
1. 通过属性访问
// 页面路径:pages/index/index.vue
<template>
<view>
<view v-for="(item, index) in todos" :key="index">
<view>{{ item.id }}</view>
<view>{{ item.text }}</view>
<view>{{ item.done }}</view>
</view>
</view>
</template>
<script>
import store from '@/store/index.js' // 需要引入 store
export default {
computed: {
todos() {
return store.getters.doneTodos
}
}
}
</script>
2. 通过 this.$store 访问
// 页面路径:pages/index/index.vue
<template>
<view>
<view v-for="(item, index) in todos" :key="index">
<view>{{ item.id }}</view>
<view>{{ item.text }}</view>
<view>{{ item.done }}</view>
</view>
</view>
</template>
<script>
export default {
computed: {
todos() {
return this.$store.getters.doneTodos
}
}
}
</script>
3. 通过方法访问
// 页面路径:pages/index/index.vue
<template>
<view>
<view v-for="(item, index) in todos" :key="index">
<view>{{ item }}</view>
</view>
</view>
</template>
<script>
export default {
computed: {
todos() {
return this.$store.getters.getTodoById(2)
}
}
}
</script>
4. 通过 mapGetters 辅助函数访问
// 页面路径:pages/index/index.vue
<template>
<view>
<view>{{ doneTodosCount }}</view>
</view>
</template>
<script>
import { mapGetters } from 'vuex' // 引入 mapGetters
export default {
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodos',
'doneTodosCount'
// ...
])
}
}
</script>
// 页面路径:pages/index/index.vue
<template>
<view>
<view>{{ doneCount }}</view>
</view>
</template>
<script>
import { mapGetters } from 'vuex' // 引入 mapGetters
export default {
computed: {
...mapGetters({
// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
}
}
</script>
Mutation
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
add(state) {
// 变更状态
state.count += 2
}
}
})
export default store
调用 Mutation
// 页面路径:pages/index/index.vue
<template>
<view>
<view>数量:{{ count }}</view>
<button @click="addCount">增加</button>
</view>
</template>
<script>
import store from '@/store/index.js'
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
addCount() {
store.commit('add')
}
}
}
</script>
传入参数
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
add(state, n) {
state.count += n
}
}
})
export default store
// 页面路径:pages/index/index.vue
<template>
<view>
<view>数量:{{ count }}</view>
<button @click="addCount">增加</button>
</view>
</template>
<script>
import store from '@/store/index.js'
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
addCount() {
store.commit('add', 5) // 每次累加 5
}
}
}
</script>
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
add(state, payload) {
state.count += payload.amount
}
}
})
export default store
// 页面路径:pages/index/index.vue
<template>
<view>
<view>数量:{{ count }}</view>
<button @click="addCount">增加</button>
</view>
</template>
<script>
import store from '@/store/index.js'
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
addCount() {
// 把载荷和 type 分开提交
store.commit('add', { amount: 10 })
}
}
}
</script>
提交方式
1. 对象风格的提交方式
// 页面路径:pages/index/index.vue
<template>
<view>
<view>数量:{{ count }}</view>
<button @click="addCount">增加</button>
</view>
</template>
<script>
import store from '@/store/index.js'
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
addCount() {
// 整个对象都作为载荷传给 mutation 函数
store.commit({
type: 'add',
amount: 6
})
}
}
}
</script>
mutations: {
add(state, payload) {
state.count += payload.amount
}
}
2. 通过 mapMutations 辅助函数提交
// 页面路径:pages/index/index.vue
<template>
<view>
<view>数量:{{ count }}</view>
<button @click="add">增加</button>
</view>
</template>
<script>
import { mapMutations } from 'vuex' // 引入 mapMutations
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
...mapMutations(['add']) // 对象展开运算符直接拿到 add
}
}
</script>
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
add(state) {
// 变更状态
state.count += 2
}
}
})
export default store
state.obj = { ...state.obj, newProp: 123 }
Action
注册 Action
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
add(state) {
// 变更状态
state.count += 2
}
},
actions: {
addCountAction(context) {
context.commit('add')
}
}
})
export default store
actions: {
// 参数解构
addCountAction({ commit }) {
commit('add')
}
}
分发 Action
1. Actions 通过 store.dispatch 方法触发
// 页面路径:pages/index/index.vue
<template>
<view>
<view>数量:{{ count }}</view>
<button @click="add">增加</button>
</view>
</template>
<script>
import store from '@/store/index.js'
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
add() {
store.dispatch('addCountAction')
}
}
}
</script>
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
add(state, payload) {
state.count += payload.amount
}
},
actions: {
addCountAction(context, payload) {
context.commit('add', payload)
}
}
})
export default store
// 页面路径:pages/index/index.vue
<template>
<view>
<view>数量:{{ count }}</view>
<button @click="add">增加</button>
</view>
</template>
<script>
import store from '@/store/index.js'
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
add() {
// 以载荷形式分发
store.dispatch('addCountAction', { amount: 10 })
}
}
}
</script>
methods: {
add() {
// 以对象形式分发
store.dispatch({
type: 'addCountAction',
amount: 5
})
}
}
// 页面路径:store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
add(state) {
// 变更状态
state.count += 2
}
},
actions: {
addCountAction(context) {
// 在执行累加的时候,会等待两秒才执行
setTimeout(function () {
context.commit('add')
}, 2000)
}
}
})
export default store
2. 通过 mapActions 辅助函数分发
// 页面路径:pages/index/index.vue
<template>
<view>
<view>数量:{{ count }}</view>
<button @click="addCountAction">增加</button>
</view>
</template>
<script>
import { mapActions } from 'vuex'
export default {
computed: {
count() {
return this.$store.state.count
}
},
methods: {
...mapActions([
'addCountAction'
// 将 `this.addCountAction()` 映射为 `this.$store.dispatch('addCountAction')`
])
}
}
</script>
methods: {
...mapActions([
'addCountAction'
// 将 `this.addCountAction(amount)` 映射为
// `this.$store.dispatch('addCountAction', amount)`
])
}
methods: {
...mapActions({
addCount: 'addCountAction'
// 将 `this.addCount()` 映射为 `this.$store.dispatch('addCountAction')`
})
}
组合 Action
actions: {
actionA({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}
store.dispatch('actionA').then(() => {
// ...
})
actions: {
// ...
actionB({ dispatch, commit }) {
return dispatch('actionA').then(() => {
commit('someOtherMutation')
})
}
}
// 假设 getData() 和 getOtherData() 返回的是 Promise
actions: {
async actionA({ commit }) {
commit('gotData', await getData())
},
async actionB({ dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
commit('gotOtherData', await getOtherData())
}
}