vuex使用详情

Vuex 是 Vue 官方提供的状态管理模式,用于集中管理 Vue 应用中多个组件共享的状态(如用户信息、购物车数据等),解决组件间复杂的状态传递和共享问题。其核心思想是 “单一状态树”,将所有共享状态存储在一个集中的仓库(Store)中,通过规范的方式(Mutation、Action 等)修改状态,保证状态变更的可追踪性。

一、核心概念与工作流程

Vuex 包含 5 个核心部分,工作流程如下:组件 → dispatch(Action) → commit(Mutation) → 修改 State → 组件重新渲染

核心部分作用特点
State存储应用的共享状态(唯一数据源)类似组件的 data,但为全局共享
Getter对 State 进行计算派生(类似组件的 computed缓存结果,依赖不变时不会重新计算
Mutation唯一修改 State 的方式(同步操作)必须是同步函数,通过 commit 触发
Action处理异步操作(如接口请求),最终通过 Mutation 修改 State可包含异步逻辑,通过 dispatch 触发
Module拆分复杂状态为多个模块(每个模块包含自己的 State、Getter 等)避免单一状态树过于庞大,支持命名空间隔离

二、安装与基本配置(Vue2 + Vuex3)

Vuex 3.x 适配 Vue2,4.x 适配 Vue3,以下以 Vue2 + Vuex3 为例:

1. 安装 Vuex
npm install vuex@3  # Vue2 需指定版本 3.x
# 或
yarn add vuex@3
2. 创建 Store(核心配置)

在 src/store 目录下创建 index.js,定义 Store 实例:

// src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

// 1. 注册 Vuex 插件
Vue.use(Vuex)

// 2. 定义 State(共享状态)
const state = {
  count: 0, // 示例:计数器状态
  userInfo: null // 示例:用户信息
}

// 3. 定义 Getter(派生状态)
const getters = {
  // 计算 count 的 2 倍
  doubleCount: state => state.count * 2,
  // 判断用户是否登录
  isLogin: state => !!state.userInfo
}

// 4. 定义 Mutation(修改 State 的唯一方式)
const mutations = {
  // 增加 count(同步操作)
  INCREMENT(state, payload) { // 推荐使用大写常量命名
    state.count += payload || 1
  },
  // 设置用户信息
  SET_USER_INFO(state, userInfo) {
    state.userInfo = userInfo
  }
}

// 5. 定义 Action(处理异步,提交 Mutation)
const actions = {
  // 异步增加 count(模拟接口请求延迟)
  async incrementAsync({ commit }, payload) {
    await new Promise(resolve => setTimeout(resolve, 1000)) // 模拟异步
    commit('INCREMENT', payload) // 提交 Mutation
  },
  // 异步登录(模拟接口请求)
  async login({ commit }, userData) {
    // 模拟接口请求
    const mockUser = { id: 1, name: 'Vuex' }
    await new Promise(resolve => setTimeout(resolve, 500))
    commit('SET_USER_INFO', mockUser) // 提交 Mutation 保存用户信息
  }
}

// 6. 创建并导出 Store 实例
export default new Vuex.Store({
  state,
  getters,
  mutations,
  actions
})
3. 在 Vue 实例中注入 Store

在入口文件 main.js 中引入并注入 Store,使所有组件可访问:

// src/main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store' // 引入 Store

new Vue({
  store, // 注入 Store(所有组件可通过 this.$store 访问)
  render: h => h(App)
}).$mount('#app')

三、核心部分使用详解

1. State:访问共享状态

组件中通过 this.$store.state 访问状态,或使用 mapState 辅助函数简化写法。

基础用法

<template>
  <div>
    <p>当前计数:{{ $store.state.count }}</p>
    <p>用户信息:{{ $store.state.userInfo?.name }}</p>
  </div>
</template>

使用 mapState 映射到组件计算属性

<template>
  <div>
    <p>当前计数:{{ count }}</p> <!-- 直接使用映射后的属性 -->
    <p>用户信息:{{ userInfo?.name }}</p>
  </div>
</template>

<script>
import { mapState } from 'vuex' // 导入辅助函数

export default {
  computed: {
    // 方式 1:数组形式(属性名与 State 一致)
    ...mapState(['count', 'userInfo']),

    // 方式 2:对象形式(自定义属性名)
    ...mapState({
      currentCount: state => state.count, // 函数形式
      user: 'userInfo' // 字符串形式(等价于 state => state.userInfo)
    })
  }
}
</script>
2. Getter:派生状态计算

通过 this.$store.getters 访问,或使用 mapGetters 映射。

基础用法

<template>
  <div>
    <p>计数的 2 倍:{{ $store.getters.doubleCount }}</p>
    <p>是否登录:{{ $store.getters.isLogin ? '已登录' : '未登录' }}</p>
  </div>
</template>

使用 mapGetters 映射

<script>
import { mapGetters } from 'vuex'

export default {
  computed: {
    ...mapGetters(['doubleCount', 'isLogin']),
    // 自定义名称
    ...mapGetters({
      double: 'doubleCount' // 将 doubleCount 映射为 double
    })
  }
}
</script>
3. Mutation:修改状态(同步)

必须通过 commit 触发,不能直接修改 State(否则无法追踪状态变更)。

基础用法

<template>
  <button @click="handleIncrement">增加计数</button>
</template>

<script>
export default {
  methods: {
    handleIncrement() {
      // 触发 Mutation(无参数)
      this.$store.commit('INCREMENT')

      // 带参数(payload)
      this.$store.commit('INCREMENT', 5) // 增加 5

      // 对象形式(更清晰)
      this.$store.commit({
        type: 'INCREMENT', // Mutation 名称
        payload: 10 // 参数
      })
    }
  }
}
</script>

使用 mapMutations 映射到方法

<script>
import { mapMutations } from 'vuex'

export default {
  methods: {
    ...mapMutations(['INCREMENT']), // 映射为 this.INCREMENT()
    ...mapMutations({
      add: 'INCREMENT' // 映射为 this.add(),对应 INCREMENT Mutation
    }),
    handleClick() {
      this.INCREMENT(3) // 调用映射后的方法
      this.add(5)
    }
  }
}
</script>

注意:Mutation 必须是同步函数(若有异步逻辑,会导致状态变更无法追踪)。

4. Action:处理异步操作

通过 dispatch 触发,内部可包含异步逻辑(如接口请求),最终通过 commit 调用 Mutation 修改状态。

基础用法

<template>
  <div>
    <button @click="handleAsyncIncrement">1秒后增加计数</button>
    <button @click="handleLogin">登录</button>
  </div>
</template>

<script>
export default {
  methods: {
    handleAsyncIncrement() {
      // 触发 Action(无参数)
      this.$store.dispatch('incrementAsync')

      // 带参数
      this.$store.dispatch('incrementAsync', 5)

      // 对象形式
      this.$store.dispatch({
        type: 'incrementAsync',
        payload: 10
      })
    },
    async handleLogin() {
      // Action 支持返回 Promise,可 await
      await this.$store.dispatch('login', { username: 'test' })
      console.log('登录成功')
    }
  }
}
</script>

使用 mapActions 映射到方法

<script>
import { mapActions } from 'vuex'

export default {
  methods: {
    ...mapActions(['incrementAsync', 'login']), // 映射为 this.incrementAsync()
    ...mapActions({
      asyncAdd: 'incrementAsync' // 自定义方法名
    }),
    handleClick() {
      this.asyncAdd(3)
      this.login({ username: 'vue' })
    }
  }
}
</script>
5. Module:拆分复杂状态

当应用状态复杂时,可将 Store 拆分为多个模块(Module),每个模块包含独立的 stategettersmutationsactions

示例:定义用户模块(user.js

// src/store/modules/user.js
export default {
  namespaced: true, // 开启命名空间(避免模块间命名冲突)
  state: {
    info: null,
    token: ''
  },
  getters: {
    isLogin: state => !!state.token
  },
  mutations: {
    SET_TOKEN(state, token) {
      state.token = token
    }
  },
  actions: {
    async login({ commit }, userData) {
      // 模拟登录接口
      const mockToken = 'xxx-token'
      await new Promise(resolve => setTimeout(resolve, 500))
      commit('SET_TOKEN', mockToken)
    }
  }
}

在 Store 中注册模块

// src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user' // 导入用户模块
import cart from './modules/cart' // 假设有购物车模块

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    user, // 注册用户模块
    cart // 注册购物车模块
  }
})

访问模块中的状态

<template>
  <div>
    <!-- 访问模块 state -->
    <p>用户 token:{{ $store.state.user.token }}</p>

    <!-- 访问模块 getter(需指定模块名) -->
    <p>是否登录:{{ $store.getters['user/isLogin'] }}</p>

    <!-- 触发模块 mutation(需指定模块名) -->
    <button @click="$store.commit('user/SET_TOKEN', 'new-token')">
      设置 token
    </button>

    <!-- 触发模块 action(需指定模块名) -->
    <button @click="$store.dispatch('user/login')">
      模块登录
    </button>
  </div>
</template>

使用辅助函数访问命名空间模块

<script>
import { mapState, mapActions } from 'vuex'

export default {
  computed: {
    ...mapState('user', ['token', 'info']) // 第一个参数为模块名
  },
  methods: {
    ...mapActions('user', ['login']) // 映射 user 模块的 login Action
  }
}
</script>

四、最佳实践

  1. Mutation 命名常量:将 Mutation 名称定义为常量,避免拼写错误:

    // src/store/mutation-types.js
    export const INCREMENT = 'INCREMENT'
    
    // 在 mutations 中使用
    import { INCREMENT } from './mutation-types'
    const mutations = {
      [INCREMENT](state) { ... }
    }
    
  2. 避免直接修改 State:必须通过 Mutation 修改,否则 Vuex 无法追踪状态变更。

  3. Action 处理所有异步:异步逻辑(接口请求、定时器等)全部放在 Action 中,保持 Mutation 同步纯净。

  4. 合理拆分模块:按业务领域(用户、购物车、商品等)拆分模块,开启命名空间避免冲突。

  5. 状态持久化:通过 vuex-persistedstate 插件将状态持久化到 localStorage,避免刷新丢失:

    npm install vuex-persistedstate
    
    import createPersistedState from 'vuex-persistedstate'
    
    const store = new Vuex.Store({
      // ...其他配置
      plugins: [
        createPersistedState({
          storage: window.localStorage, // 存储到 localStorage
          reducer: (state) => ({ user: state.user }) // 只持久化 user 模块
        })
      ]
    })
    

五、适用场景

  • 多个组件共享同一状态(如用户信息、全局设置)。
  • 组件间状态传递复杂(如跨层级、非父子组件)。
  • 需要追踪状态变更(如调试、撤销 / 重做功能)。

总结

Vuex 通过 “单一状态树” 集中管理共享状态,核心流程是:组件通过 dispatch 触发 Action 处理异步,Action 通过 commit 调用 Mutation 同步修改 State,最终 State 变更驱动组件重新渲染。合理使用 Module 拆分状态、遵循同步 / 异步分离原则,可有效管理复杂应用的状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值