Vuex 4的基本使用
Vuex 是什么?
官方说法:
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
我的理解:
Vuex 是用来帮助我们存放一些需要在多个地方使用的数据,以方便我们更好地使各个组件中的数据互相传递,即使他们在不同的层次中。
举个例子:
如下图,由于各个组件的层次不同,如果我们想将黄色块中的hotdog数据分享到红色块中,需要通过多个组件一个个逐次传递,即便部分组件并不需要hotdog数据。
而Vuex则可以将该hotdog储存起来,各个组件即使在不同从层次,也只需要调用Vuex中的数据即可拿到hotdog数据,数据传输就像呼吸一般自然,相当不错。
Vuex 基本使用方法
- 安装Vuex:通过npm或yarn等包管理工具安装Vuex。
npm install vuex@next --save
- 创建一个Vuex store:store是Vuex中最核心的概念,它包含了应用中的所有状态。通过createStore方法创建一个store实例。
import { createStore } from 'vuex'
const store = createStore({
state() {
return {
count: 0
}
},
mutations: {
increment(state) {
state.count++
}
}
})
在上面的代码中,我们定义了一个状态count和一个mutation函数increment,用于对count进行加1操作。
- 注册store:在Vue应用的根组件中注册store,使得整个应用都可以使用Vuex中定义的状态和操作。
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
const app = createApp(App)
app.use(store)
app.mount('#app')
在上面的代码中,我们通过Vue的createApp方法创建一个Vue实例,并在实例中使用了刚才创建的store。
- 使用state:在组件中使用Vuex中的状态,可以通过计算属性或直接在模板中使用$store来获取。
<template>
<div>
<p>{{ count }}</p>
<button @click="$store.commit('increment')">+</button>
</div>
</template>
<script>
export default {
computed: {
count() {
return this.$store.state.count
}
}
}
</script>
在上面的代码中,我们定义了一个计算属性count,用于获取Vuex中的状态count。在模板中,我们通过$store.commit方法来调用刚才定义的increment函数。
这就是Vuex 4的基本使用方法,当然Vuex还提供了很多高级用法,如actions、getters等,可以根据具体需求来选择使用。
Vuex的高级用法
1. Getter 计算属性缓存
类似于 Vue 中的计算属性,用于对 state 进行计算和处理,并且支持缓存。
示例代码:
const store = new Vuex.Store({
state: {
count: 1
},
getters: {
getCount: state => state.count,
doubleCount: state => state.count * 2
}
})
// 获取 count
console.log(store.getters.getCount) // 输出 1
// 获取 doubleCount,由于 doubleCount 有缓存,所以只会输出一次
console.log(store.getters.doubleCount) // 输出 2
console.log(store.getters.doubleCount) // 不会输出,直接返回上一次的值 2
2. Action
类似于 Mutation,但是可以执行异步操作,并且可以提交 Mutation 来更新 state。
示例代码:
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment: state => state.count++
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
})
// 执行 incrementAsync action
store.dispatch('incrementAsync')
3. 模块化
如果 Vuex 中的状态过多,为了方便管理和维护,可以将状态拆分成多个模块。每个模块包含自己的状态、mutations、actions 和 getters。
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
4. 动态注册模块
如果希望在 store 创建之后动态添加模块,可以使用 store.registerModule() 方法。这个方法接收两个参数,第一个参数是一个字符串,用于指定模块的名称;第二个参数是一个对象,包含模块的状态、mutations、actions 和 getters。例如:
const store = new Vuex.Store({ /* ... */ })
store.registerModule('myModule', {
state: { /* ... */ },
mutations: { /* ... */ },
actions: { /* ... */ },
getters: { /* ... */ }
})
5. 使用插件
Vuex 插件是一个函数,它接收 store 作为唯一参数,并可以访问 state,getters,mutations 和 actions。插件可以用来拦截、修改、甚至代理 store 的某些行为。例如:
const myPlugin = store => {
// 在每次 mutation 之后打印状态变化
store.subscribe((mutation, state) => {
console.log(`mutation ${mutation.type}, state: ${JSON.stringify(state)}`)
})
}
将插件作为第二个参数传入 Vuex.Store 的构造函数。
const store = new Vuex.Store({
// ...
plugins: [myPlugin]
})
6. 使用动态命名空间
可以将模块的命名空间设置为一个函数,使其能够在模块注册时动态生成。这个函数将接收模块本身作为其唯一参数,并返回一个字符串来表示该模块的命名空间。例如:
const myModule = {
namespaced: true,
getters: {
myGetter: (state, getters, rootState, rootGetters) => {
// ...
}
}
}
const store = new Vuex.Store({
modules: {
['myModule/' + Math.random().toString(36).substring(2)]: myModule
}
})
7. 自定义 subscribe
Vuex 的 store.subscribe() 方法用于订阅 store 中的
mutation。如果需要自定义这个行为,可以通过重新实现 subscribe 方法来实现。例如:
const store = new Vuex.Store({ /* ... */ })
store.subscribe = (fn, options) => {
const unsubscribe = store._subscribe(fn, options)
// 每次订阅后延迟 1 秒钟执行一次取消订阅
setTimeout(() => {
unsubscribe()
}, 1000)
}
8. 严格模式
Vuex 提供了严格模式(strict mode)来帮助开发者调试应用。在严格模式下,任何对 store 的修改必须通过 mutation 进行,否则将会抛出错误。
const store = new Vuex.Store({
state: { ... },
mutations: { ... },
strict: true
})
9. 热重载
在开发过程中,如果对 store 进行了修改,可以使用 vuex 的热重载功能,使得代码修改后立即生效。
if (module.hot) {
// 使 mutations 和 modules 成为可热重载模块
module.hot.accept(['./mutations', './modules'], () => {
// 获取更新后的模块
const newMutations = require('./mutations').default
const newModules = require('./modules').default
// 安装新模块
store.hotUpdate({
mutations: newMutations,
modules: newModules
})
})
}