第Ⅶ章-Ⅰ Vuex详解
简介
Vuex 是一个专为 Vue.js 应用设计的状态管理模式。它允许你将应用中共享的状态提取出来进行集中管理,并以相应的规则保证状态以一种可预测的方式发生变化。
- State:存储应用状态数据。
- Getters:从 state 派生出计算属性,类似于组件的 computed 属性。
- Mutations:同步修改 state 的方法。
- Actions:包含异步操作的函数,可调用 mutations 以最终修改 state。
- Modules:将状态和业务逻辑分割到独立模块中。
vite 引入 vuex
npm
npm install vuex@next
yarn
yarn add vuex@next
创建一个 store 目录并新建 index.ts 文件
// src/store/index.ts
import { createStore } from 'vuex';
// 创建 Vuex 仓库
const store = createStore({
state: {
count: 0
},
mutations: {
increment(state) {
state.count += 1;
},
decrement(state) {
state.count -= 1;
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment');
}, 1000);
}
},
getters: {
doubleCount(state) {
return state.count * 2;
}
}
});
export default store;
在 main.ts 中引入并使用 store
// src/main.ts
import { createApp } from 'vue';
import App from './App.vue';
import store from './store';
const app = createApp(App);
app.use(store);
app.mount('#app');
vuex的使用
<template>
<div>
<h1>Vuex 使用示例</h1>
<p>Count: {{ count }}</p>
<p>Double Count (getter): {{ doubleCount }}</p>
<button @click="increment">Increment</button>
<button @click="decrement">Decrement</button>
<button @click="incrementAsync">Increment Async</button>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { useStore } from 'vuex';
// 使用 Vuex 仓库
const store = useStore();
// 计算属性
const count = computed(() => store.state.count);
const doubleCount = computed(() => store.getters.doubleCount);
// 方法
const increment = () => store.commit('increment');
const decrement = () => store.commit('decrement');
const incrementAsync = () => store.dispatch('incrementAsync');
</script>
Vuex核心概念
state
state 是 Vuex 中的数据源,存储应用的共享状态。通过组件访问 state 中的值,可以实现数据共享。
// store/index.ts
const store = createStore({
state: {
count: 0,
user: {
name: 'Alice',
age: 30
}
}
});
多个组件需要访问相同的数据(例如,用户信息,购物车状态)。
getters
getters 类似于计算属性,它从 state 中派生出一些属性,并可在组件中直接访问。
// store/index.ts
const store = createStore({
state: {
items: [
{ name: 'item1', price: 10 },
{ name: 'item2', price: 20 },
{ name: 'item3', price: 15 }
]
},
getters: {
totalPrice(state) {
return state.items.reduce((total, item) => total + item.price, 0);
}
}
});
<!-- src/App.vue -->
<template>
<div>
<h1>Shopping Cart</h1>
<ul>
<li v-for="item in items" :key="item.name">{{ item.name }} - ${{ item.price }}</li>
</ul>
<h2>Total Price: ${{ totalPrice }}</h2>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { useStore } from 'vuex';
// 获取 Vuex Store 实例
const store = useStore();
// 计算属性来获取 Vuex 状态和 Getters
const items = computed(() => store.state.items);
const totalPrice = computed(() => store.getters.totalPrice);
</script>
从 state 中派生出需要频繁使用的计算属性(例如,计算总价格、过滤列表)。
mutations
mutations 是唯一允许同步更改 state 数据的地方。它接收两个参数:state 和 payload(可选)。
// store/index.ts
interface User{
name:string;
age:number;
}
interface State{
user:User;
}
const store = createStore<State>({
state: {
user: {
name: 'Alice',
age: 30
}
},
mutations: {
updateUser(state, payload:Partial<User>) {
state.user = { ...state.user, ...payload };
}
}
});
提示:...用于对象合并 避免了元对象属性的丢失。 Partial<User> 而不是直接使用 User,是为了支持部分更新的功能。
<!-- src/App.vue -->
<template>
<div>
<h1>User Information</h1>
<p>Name: {{ user.name }}</p>
<p>Age: {{ user.age }}</p>
<h2>Update User Information</h2>
<input v-model="newName" placeholder="New Name" />
<input v-model.number="newAge" placeholder="New Age" type="number" />
<button @click="updateUserInfo">Update User</button>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
import { useStore } from 'vuex';
// 获取 Vuex Store 实例
const store = useStore();
// 计算属性访问 Vuex 状态
const user = computed(() => store.state.user);
// 输入框绑定的数据
const newName = ref(user.value.name);
const newAge = ref(user.value.age);
// 更新用户信息
const updateUserInfo = () => {
store.commit('updateUser', {
name: newName.value,
age: newAge.value
});
};
</script>
需要同步改变共享状态时(例如,更新用户信息、添加商品到购物车)。
actions
actions 类似于 mutations,但它允许异步操作。可以在 actions 中发起网络请求或执行其他异步任务,然后再调用 mutations。
// store/index.ts
// store/index.ts
const store = createStore({
state: {
user: null
},
mutations: {
setUser(state, user) {
state.user = user;
}
},
actions: {
async fetchUser({ commit }) {
const response = await fetch('https://api.example.com/user');
const user = await response.json();
commit('setUser', user);
}
}
});
需要异步改变共享状态时(例如,获取服务器数据并更新到状态中)。。
modules
modules 允许我们将 Vuex 的 state、mutations、actions 和 getters 分割成更小的模块,从而实现状态的模块化管理。
// store/modules/counter.ts
import { Module } from 'vuex';
const counterModule: Module<any, any> = {
namespaced: true,
state: {
count: 0
},
mutations: {
increment(state) {
state.count += 1;
},
decrement(state) {
state.count -= 1;
}
},
getters: {
doubleCount(state) {
return state.count * 2;
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment');
}, 1000);
}
}
};
export default counterModule;
在全局store中使用模块
// store/index.ts
import { createStore } from 'vuex';
import counterModule from './modules/counter';
const store = createStore({
modules: {
counter: counterModule
}
});
export default store;
组件使用模块状态
<template>
<div>
<h2>Counter Module Example</h2>
<p>Count: {{ count }}</p>
<p>Double Count (getter): {{ doubleCount }}</p>
<button @click="increment">Increment</button>
<button @click="decrement">Decrement</button>
<button @click="incrementAsync">Increment Async</button>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { useStore } from 'vuex';
const store = useStore();
const count = computed(() => store.state.counter.count);
const doubleCount = computed(() => store.getters['counter/doubleCount']);
const increment = () => store.commit('counter/increment');
const decrement = () => store.commit('counter/decrement');
const incrementAsync = () => store.dispatch('counter/incrementAsync');
</script>
提示:模块名称作为命名空间前缀在组件中调用 Vuex 模块的 mutations、actions 和 getters 时,需要在名称前加上模块名称。例如,counter/increment、counter/doubleCount。模块注册在全局 store 中你需要在全局的 Vuex store 实例中将模块注册为一个 module,这样才能在组件中访问它们的状态。
拓展
actions 和 mutations区别
mutations:
- 只能进行同步操作。
- 直接修改 state。
- 使用 commit 来调用。
- 每个 mutation 都会生成一个新的状态快照,方便调试工具追踪状态变化。
actions:
- 支持异步操作。
- 不直接修改 state,通过提交 mutations 来修改状态。
- 使用 dispatch 来调用。
- 可以包含复杂的逻辑,比如 API 请求、异步任务等。