← 目录从零开始学vue3

状态管理(vuex)

2024/9/17

Vue 3 的 setup 函数与 Vuex 4 的结合,为状态管理提供了简洁且灵活的方案。Vuex 4 保持了与 Vuex 3 类似的 API,但针对 Vue 3 进行了优化。以下详细介绍 Vuex 4 在 Vue 3 setup 语法中的使用,并提供具体的示例说明。

一、Vuex 的安装与基本配置

1. 安装 Vuex 4

首先,需要在 Vue 3 项目中安装 Vuex 4:

bash
npm install vuex@next

2. 创建 Vuex Store

在项目中创建一个 store/index.js 文件,用于配置 Vuex Store:

js
import { createStore } from 'vuex';

export default createStore({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    },
    setCount(state, payload) {
      state.count = payload;
    }
  },
  actions: {
    incrementAsync({ commit }) {
      setTimeout(() => {
        commit('increment');
      }, 1000);
    }
  },
  getters: {
    doubleCount(state) {
      return state.count * 2;
    }
  }
});

二、在 Vue 3 中使用 Vuex

1. 在 main.js 中注册 Vuex

在 main.js 中引入并注册 Vuex:

js
import { createApp } from 'vue';
import App from './App.vue';
import store from './store'; // 引入 Vuex store

const app = createApp(App);
app.use(store); // 使用 Vuex
app.mount('#app');

2. 在 setup 中使用 Vuex

在 setup 中,Vuex Store 可以通过 useStore 函数直接访问。

vue
<template>
  <div>
    <h1>当前计数:{{ count }}</h1>
    <h2>双倍计数:{{ doubleCount }}</h2>
    <button @click="increment">增加计数</button>
    <button @click="incrementAsync">异步增加计数</button>
  </div>
</template>

<script>
import { defineComponent } from 'vue';
import { useStore } from 'vuex';

export default defineComponent({
  setup() {
    const store = useStore(); // 获取 store 实例
    const count = store.state.count; // 访问 state
    const doubleCount = store.getters.doubleCount; // 访问 getter

    const increment = () => {
      store.commit('increment'); // 同步触发 mutation
    };

    const incrementAsync = () => {
      store.dispatch('incrementAsync'); // 异步触发 action
    };

    return {
      count,
      doubleCount,
      increment,
      incrementAsync
    };
  }
});
</script>

三、详细示例说明

1. State 和 Getters 的使用

Vuex 中的 state 用来存储应用的全局状态。在 setup 函数中,可以通过 store.state 来访问状态,同时可以通过 store.getters 来访问处理过的状态。

示例:

vue
<template>
  <div>
    <h1>当前数量:{{ count }}</h1>
    <h2>双倍数量:{{ doubleCount }}</h2>
  </div>
</template>

<script>
import { defineComponent } from 'vue';
import { useStore } from 'vuex';

export default defineComponent({
  setup() {
    const store = useStore();
    const count = store.state.count; // 访问全局状态
    const doubleCount = store.getters.doubleCount; // 访问计算属性(getter)

    return {
      count,
      doubleCount
    };
  }
});
</script>

2. Mutations 和 Actions 的使用

mutations 是 Vuex 中唯一能改变状态的方式,而 actions 则用于处理异步逻辑。在 setup 中,使用 store.commit 触发 mutations,使用 store.dispatch 触发 actions。

示例:

vue
<template>
  <div>
    <h1>当前数量:{{ count }}</h1>
    <button @click="increment">增加</button>
    <button @click="incrementAsync">异步增加</button>
  </div>
</template>

<script>
import { defineComponent } from 'vue';
import { useStore } from 'vuex';

export default defineComponent({
  setup() {
    const store = useStore();

    const increment = () => {
      store.commit('increment'); // 同步触发 mutation
    };

    const incrementAsync = () => {
      store.dispatch('incrementAsync'); // 异步触发 action
    };

    return {
      count: store.state.count,
      increment,
      incrementAsync
    };
  }
});
</script>

四、Vuex 模块化

在大型应用中,状态管理的复杂性会随之增加,Vuex 提供了模块化的方式来组织代码。

1. 模块化 Vuex Store

在 store/index.js 中,可以按模块组织 state、mutations、actions 和 getters:

js
import { createStore } from 'vuex';

const userModule = {
  namespaced: true, // 开启命名空间
  state: {
    username: 'admin'
  },
  mutations: {
    setUsername(state, username) {
      state.username = username;
    }
  },
  actions: {
    updateUsername({ commit }, username) {
      commit('setUsername', username);
    }
  },
  getters: {
    userInitials(state) {
      return state.username.charAt(0).toUpperCase();
    }
  }
};

const store = createStore({
  modules: {
    user: userModule // 注册模块
  }
});

export default store;

2. 在组件中使用模块化 Store

如果模块开启了命名空间,可以通过模块名访问状态和方法。

vue
<template>
  <div>
    <h1>用户名:{{ username }}</h1>
    <h2>用户首字母:{{ userInitials }}</h2>
    <input v-model="newUsername" placeholder="输入新用户名" />
    <button @click="updateUsername">更新用户名</button>
  </div>
</template>

<script>
import { defineComponent, ref } from 'vue';
import { useStore } from 'vuex';

export default defineComponent({
  setup() {
    const store = useStore();
    const newUsername = ref('');

    const updateUsername = () => {
      store.dispatch('user/updateUsername', newUsername.value); // 使用模块命名空间
    };

    return {
      username: store.state.user.username,
      userInitials: store.getters['user/userInitials'], // 使用命名空间的 getter
      newUsername,
      updateUsername
    };
  }
});
</script>

五、Vuex 4 与 setup 的使用总结

  1. State 和 Getters: 通过 store.state 和 store.getters 访问全局状态和计算属性。
  2. Mutations 和 Actions: 使用 store.commit 触发同步 mutations,使用 store.dispatch 触发异步 actions。
  3. 模块化管理: 使用模块化管理状态,通过 namespaced 实现命名空间,方便状态的划分和管理。
  4. Vuex 与 setup 的结合: 通过 useStore 在 setup 函数中访问 Vuex,保持代码简洁。

六、Vuex 4 在实际场景中的应用

Vuex 适用于需要在不同组件之间共享状态的场景,尤其是在大型项目中,可以通过 Vuex 实现全局状态的管理,如用户认证状态、应用配置、购物车、权限控制等。通过 Vuex 的模块化和命名空间,可以将不同的业务逻辑模块化,增强代码的可维护性和可扩展性。