参考文档:
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
这个状态自管理应用包含以下几个部分:
Vuex的工作原理如下图所示:
import { createApp } from 'vue' import { createStore } from 'vuex' // 创建一个新的 store 实例 const store = createStore({ state () { return { count: 0 } }, getters: { double(state){ return state.count * 2 } }, mutations: { increment (state, payload) { state.count++ } }, actions: { AsyncIncrement(state, payload){ return new Promise((resolve, reject) => { setTimeout(() => { commit('someMutation', payload) resolve() }, 1000) }) } } }) const app = createApp({ /* 根组件 */ }) // 将 store 实例作为插件安装 app.use(store)
import { computed } from 'vue' import { useStore } from 'vuex' export default { setup () { const store = useStore() return { // 在 computed 函数中访问 state count: computed(() => store.state.count), // 在 computed 函数中访问 getter double: computed(() => store.getters.double) } } }
import { useStore } from 'vuex' export default { setup () { const store = useStore() return { // 使用 mutation increment: () => store.commit('increment'), // 使用 action asyncIncrement: () => store.dispatch('asyncIncrement') } } }
store
的方法不同,之前是通过new Store()
来创建一个 store
实例。现在是通过 createStore
方法来创建。useStore
这个函数。createStore
方法store实际上还是基于一个Class
来实现的,只是没有直接将 Store
这个类暴露出来,而是包装成了一个函数,直接返回实例。
import { reactive } from 'vue' export function createStore(options){ return new Store(options) } class Store{ constructor(options){ const store = this; // 使用reactive使state是响应式的 store._state = reactive({data: options.state}) } get state(){ return this._state.data } }
Object.defineProperty
来重新定义getters将用户传入的getters
全部定义到store实例的getters属性上,在获取值的时候调用
function forEachValue(obj, fn){ Object.keys(obj).forEach(key => fn(obj[key], key)) } class Store{ constructor(options){ const store = this; // 使用reactive使state是响应式的 store._state = reactive({data: options.state}) // 保存getters const _getters = options.getters; store.getters = {}; forEachValue(_getters, function(fn, key){ Object.defineProperty(store.getters, key, { get: ()=> fn(store.state), enumerable: true }) }) } }
mutations
和 actions
class Store{ constructor(options){ // ... const store = this; store._mutations = Object.create(null) const _mutations = options.mutations; forEachValue(_mutations, (mutation, key)=>{ store._mutations[key] = (payload) => { mutation.call(store, store.state, payload) } }) } commit = (type, payload) => { this._mutations[type](payload) } }
Action 类似于 mutation,不同在于:
由于action可以执行异步函数,所以action在执行完成后应该返回一个Promise实例,对dispact的执行结果进行判断,如果不是一个Promise,需要给处理成一个promise。
class Store{ constructor(options){ // ... const store = this; store._actions = Object.create(null) const _actions = options.actions; forEachValue(_actions, (action, key)=>{ store._actions[key] = (payload) => { const res = action.call(store, store.state, payload) if(!isPromise(res)){ return Promise.resolve(res) } return res } }) } dispatch = (type, payload) => { this._actions[type](payload) } }
通过inject
来获取注册的store实例
import {inject} from 'vue' export function useStore(injectKey = null) { return inject('store') }
在Vue项目中使用Vuex,我们需要通过use()
来注册store
const app = createApp({ /* 根组件 */ }) // 将 store 实例作为插件安装 app.use(store)
class Store{ install(app, injectKey){ // Vue3.x createApp().use(store) // 全局暴露一个 变量,暴露的是store的实例 app.provide('store') // Vue2.x Vue.prototype.$store = this // 增添$store属性 使得可以直接在模板中使用 $store.state.count app.config.globalProperties.$store = this; } }