Vue学习笔记集--Vuex
Vuex
Vuex 是 Vue.js 的官方状态管理库,用于集中管理组件间共享的状态(数据)。
它通过单一数据源(store)实现数据的响应式管理和可预测的状态变更。
核心概念
概念 | 作用 | 特点 |
---|---|---|
State | 存储应用的状态数据(类似组件的 data ) | 唯一数据源,响应式 |
Getters | 从 state 派生的计算属性(类似组件的 computed ) | 缓存结果,避免重复计算 |
Mutations | 唯一修改 state 的方法(同步操作) | 通过 commit 触发 |
Actions | 处理异步操作或复杂逻辑,提交 mutation 间接修改 state | 通过 dispatch 触发 |
Modules | 将 store 拆分为多个模块,便于管理大型应用的状态 | 支持嵌套和命名空间(namespaced) |
基本使用
安装与配置
npm install vuex@next # Vue 3 使用 vuex@4
npm install vuex@3 # Vue 2 使用 vuex@3
创建 Store
// store/index.js
import { createStore } from 'vuex';
const store = createStore({
state: {
count: 0,
user: { name: 'Alice' }
},
getters: {
doubleCount: (state) => state.count * 2,
},
mutations: {
increment(state) {
state.count++;
},
setUser(state, payload) {
state.user = payload;
}
},
actions: {
async fetchUser({ commit }, userId) {
const user = await api.getUser(userId);
commit('setUser', user);
}
},
modules: {
// 模块化示例见下文
}
});
export default store;
挂载到 Vue 实例
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import store from './store';
const app = createApp(App);
app.use(store); // 注入全局 $store
app.mount('#app');
组件中使用 Vuex
State
存储数据
<template>
<div>{{ $store.state.count }}</div>
<div>{{ userName }}</div>
</template>
<script setup>
import { computed } from 'vue';
import { useStore } from 'vuex';
const store = useStore();
const userName = computed(() => store.state.user.name);
</script>
Vuex 的 state 是 Vuex 存储数据的地方,它提供了一种集中式的存储机制,让 Vue 组件能够方便地访问和共享状态。以下是 Vuex 的 state 的使用方法:
定义 state
在 Vuex store 中定义 state,state 是一个对象,用于存储应用的状态数据。
const store = new Vuex.Store({
state: {
count: 0,
todos: [
{ id: 1, text: 'Learn JavaScript', done: false },
{ id: 2, text: 'Learn Vue', done: false },
{ id: 3, text: 'Build a Vue App', done: false }
]
}
})
在组件中访问 state
可以通过 this.$store.state
或者 mapState
辅助函数在组件中访问 state 中的数据。
直接访问
export default {
computed: {
count() {
return this.$store.state.count;
},
todos() {
return this.$store.state.todos;
}
}
}
使用 mapState 辅助函数
import { mapState } from 'vuex';
export default {
computed: {
...mapState([
'count',
'todos'
])
}
}
修改 state
Vuex 的 state 是响应式的,但只能通过提交 mutation 来修改 state,直接修改 state 不会触发视图更新。
// 提交 mutation
this.$store.commit('increment');
// 或者在组件中使用 methods
methods: {
increment() {
this.$store.commit('increment');
}
}
对应的 mutation 定义如下:
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
}
})
使用模块化 Vuex
在大型应用中,可以将 Vuex store 拆分成多个模块,每个模块有自己的 state、mutations、actions 等。
const moduleA = {
namespaced: true,
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
}
}
const store = new Vuex.Store({
modules: {
a: moduleA
}
})
在组件中访问模块的 state:
computed: {
count() {
return this.$store.state.a.count;
}
}
或者使用 mapState
辅助函数:
import { mapState } from 'vuex';
export default {
computed: {
...mapState('a', [
'count'
])
}
}
动态注册模块
可以在应用运行时动态注册模块,方便在需要时添加新的功能。
// 动态注册模块
store.registerModule('b', {
state: {
name: 'Module B'
}
})
// 在组件中访问
computed: {
name() {
return this.$store.state.b.name;
}
}
通过以上方法,可以在 Vue 组件中方便地使用 Vuex 的 state,实现数据的集中管理和共享。
Getters
Vuex 中的 Getters 是用于从 Store 的 state 中派生出状态的计算属性,类似于组件内的 computed
属性。
基本用法
-
定义 Getter:在 Store 的
getters
对象中定义函数,接收state
作为第一个参数。const store = new Vuex.Store({ state: { todos: [ { id: 1, done: true }, { id: 2, done: false } ] }, getters: { doneTodos: state => state.todos.filter(todo => todo.done) } });
-
访问 Getter:通过
this.$store.getters.doneTodos
或mapGetters
辅助函数映射到组件计算属性。// 组件中 computed: { ...mapGetters(['doneTodos']) }
参数与依赖
-
访问其他 Getter:通过第二个参数
getters
获取其他 Getter。getters: { doneCount: (state, getters) => getters.doneTodos.length }
-
模块中的 Getter:在模块内,可访问模块的
state
、根节点的rootState
和rootGetters
。getters: { combinedData(state, getters, rootState, rootGetters) { // 访问模块和根状态 } }
动态参数
-
返回函数:通过返回函数实现传参,例如根据 ID 查找特定项。
getters: { getTodoById: state => id => state.todos.find(todo => todo.id === id) } // 使用:store.getters.getTodoById(2)
响应式与缓存
- 响应式更新:当依赖的
state
变化时,Getter 自动重新计算。 - 缓存机制:结果会被缓存,除非依赖的
state
发生变化,避免重复计算。
Mutation
在 Vuex 中,Mutations 是更改 store 中状态的唯一方式。它们是同步的事务,用于修改 state。以下是如何定义和使用 Mutations 的详细步骤:
定义和使用 Mutations
1. 定义 Mutations
在 Vuex store 中定义 Mutations。Mutations 是一个对象,其中的每个属性是一个函数,这些函数接收 state 作为第一个参数,或者通过参数解构来获取 state 和其他上下文信息。
const store = new Vuex.Store({
state: {
count: 0,
todos: []
},
mutations: {
// 简单的 mutation
increment(state) {
state.count++;
},
// 带参数的 mutation
incrementBy(state, amount) {
state.count += amount;
},
// 修改 todos
setTodos(state, todos) {
state.todos = todos;
}
}
});
2. 在组件中提交 Mutations
可以在组件中通过 this.$store.commit
提交 Mutations。
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
<button @click="incrementBy">Increment By 5</button>
<ul>
<li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li>
</ul>
</div>
</template>
<script>
export default {
computed: {
count() {
return this.$store.state.count;
},
todos() {
return this.$store.state.todos;
}
},
methods: {
increment() {
this.$store.commit('increment');
},
incrementBy() {
this.$store.commit('incrementBy', 5);
},
fetchTodos() {
// 模拟异步操作
setTimeout(() => {
this.$store.commit('setTodos', [
{ id: 1, text: 'Learn JavaScript' },
{ id: 2, text: 'Learn Vue' }
]);
}, 1000);
}
},
created() {
this.fetchTodos();
}
};
</script>
使用 mapMutations
辅助函数
为了简化代码,Vuex 提供了 mapMutations
辅助函数,可以将 store 中的 Mutations 映射到组件的方法中。
import { mapMutations } from 'vuex';
export default {
methods: {
...mapMutations([
'increment',
'incrementBy',
'setTodos'
])
}
};
这样,你就可以直接在组件中使用 increment
、incrementBy
和 setTodos
方法,而不需要显式地写 this.$store.commit
。
Mutations 的参数传递
如果需要向 Mutation 传递参数,可以在 commit
中作为第二个参数传入。
// 在组件中
this.$store.commit('incrementBy', 5);
// 在 store 的 Mutations 中
incrementBy(state, amount) {
state.count += amount;
}
Mutations 的返回值
Mutations 本身没有返回值,但你可以在提交 Mutation 后执行其他操作。
在 Mutations 中访问 state 和 getters
在 Mutations 中,可以通过参数解构来访问 state 和 getters。
mutations: {
someMutation({ state, getters }) {
console.log(state.count);
console.log(getters.doubleCount);
}
}
模块化 Vuex 中的 Mutations
在模块化 Vuex 中,Mutations 可以定义在模块内部。
const moduleA = {
namespaced: true,
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
}
};
const store = new Vuex.Store({
modules: {
a: moduleA
}
});
在组件中提交模块的 Mutation:
this.$store.commit('a/increment');
或者使用 mapMutations
:
import { mapMutations } from 'vuex';
export default {
methods: {
...mapMutations('a', [
'increment'
])
}
};
总结
- Mutations 是更改 Vuex store 中状态的唯一方式。
- 在组件中通过
this.$store.commit
提交 Mutations。 - 可以使用
mapMutations
辅助函数简化代码。 - Mutations 可以接收参数,并在模块化 Vuex 中定义在模块内部。
Action
在 Vuex 中,actions 用于处理异步操作,并可以包含逻辑来提交 mutations,从而更新 state。actions 是 Vuex 中处理业务逻辑的主要场所。
定义和使用 actions
1. 定义 actions
在 Vuex store 中定义 actions。actions 是一个对象,其中的每个属性是一个函数,这些函数接收一个上下文对象作为参数,或者通过参数解构来获取 commit
、getters
等。
const store = new Vuex.Store({
state: {
count: 0,
todos: []
},
mutations: {
increment(state) {
state.count++;
},
setTodos(state, todos) {
state.todos = todos;
}
},
actions: {
// 简单的 action
increment({ commit }) {
commit('increment');
},
// 带参数的 action
incrementBy({ commit }, amount) {
commit('incrementBy', amount);
},
// 异步 action
fetchTodos({ commit }) {
// 模拟异步操作
return new Promise((resolve) => {
setTimeout(() => {
commit('setTodos', [
{ id: 1, text: 'Learn JavaScript' },
{ id: 2, text: 'Learn Vue' }
]);
resolve();
}, 1000);
});
}
}
});
2. 在组件中使用 actions
可以在组件中通过 this.$store.dispatch
触发 actions。
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
<button @click="fetchTodos">Fetch Todos</button>
<ul>
<li v-for="todo in todos" :key="todo.id">{{ todo.text }}</li>
</ul>
</div>
</template>
<script>
export default {
computed: {
count() {
return this.$store.state.count;
},
todos() {
return this.$store.state.todos;
}
},
methods: {
increment() {
this.$store.dispatch('increment');
},
fetchTodos() {
this.$store.dispatch('fetchTodos').then(() => {
console.log('Todos fetched!');
});
}
}
};
</script>
使用 mapActions
辅助函数
为了简化代码,Vuex 提供了 mapActions
辅助函数,可以将 store 中的 actions 映射到组件的方法中。
import { mapActions } from 'vuex';
export default {
methods: {
...mapActions([
'increment',
'fetchTodos'
])
}
};
这样,你就可以直接在组件中使用 increment
和 fetchTodos
方法,而不需要显式地写 this.$store.dispatch
。
actions 的参数传递
如果需要向 action 传递参数,可以在 dispatch
中作为第二个参数传入。
// 在组件中
this.$store.dispatch('incrementBy', 5);
// 在 store 的 actions 中
incrementBy({ commit }, amount) {
commit('incrementBy', amount);
}
actions 的返回值
dispatch
会返回一个 Promise,因此可以在触发 action 后使用 .then()
或 async/await
来处理异步操作的结果。
this.$store.dispatch('fetchTodos').then(() => {
console.log('Todos fetched!');
});
在 actions 中访问 state 和 getters
在 actions 中,可以通过上下文对象访问 state 和 getters。
actions: {
someAction({ state, getters }) {
console.log(state.count);
console.log(getters.doubleCount);
}
}
模块化 Vuex 中的 actions
在模块化 Vuex 中,actions 可以定义在模块内部。
const moduleA = {
namespaced: true,
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
increment({ commit }) {
commit('increment');
}
}
};
const store = new Vuex.Store({
modules: {
a: moduleA
}
});
在组件中触发模块的 action:
this.$store.dispatch('a/increment');
或者使用 mapActions
:
import { mapActions } from 'vuex';
export default {
methods: {
...mapActions('a', [
'increment'
])
}
};
总结
- actions 用于处理异步操作和业务逻辑。
- 在组件中通过
this.$store.dispatch
触发 actions。 - 可以使用
mapActions
辅助函数简化代码。 - actions 可以接收参数,并返回 Promise。
- 在模块化 Vuex 中,actions 可以定义在模块内部,并通过命名空间访问。
辅助函数(简化代码)
Vuex 提供 mapState
, mapGetters
, mapMutations
, mapActions
辅助函数。
<script>
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
export default {
computed: {
...mapState(['count']),
...mapGetters(['doubleCount']),
},
methods: {
...mapMutations(['increment']),
...mapActions(['fetchUser']),
}
};
</script>
模块化(Modules)
定义模块
// store/modules/user.js
const userModule = {
namespaced: true, // 启用命名空间
state: () => ({ name: 'Guest' }),
mutations: {
setName(state, name) {
state.name = name;
}
},
actions: {
login({ commit }, name) {
commit('setName', name);
}
}
};
export default userModule;
注册模块
// store/index.js
import userModule from './modules/user';
const store = createStore({
modules: {
user: userModule
}
});
访问模块内容
// 组件中使用命名空间访问
store.commit('user/setName', 'Charlie');
store.dispatch('user/login', 'David');
// 辅助函数指定命名空间
...mapMutations('user', ['setName']),
...mapActions('user', ['login']),
核心原则
- 单一数据源:所有共享状态集中存储在
state
中。 - 状态只读:不允许直接修改
state
,必须通过mutations
。 - 同步修改:
mutations
必须是同步函数,确保状态变更可追踪。 - 异步操作:异步逻辑放在
actions
中,通过提交mutations
修改状态。