目录

VueVue状态管理Vuex核心概念详解从超市购物车理解Vuex

【Vue】Vue状态管理:Vuex核心概念详解(从超市购物车理解Vuex)


一、为什么需要Vuex?

1.1 组件传参的困境

假设你在开发一个电商网站:

组件A (商品列表)需要传递用户选择的商品到 组件B (购物车)

组件C (订单页)也需要访问购物车数据

当用户在不同页面间跳转时,需要保持购物车数据同步

使用传统 props/$emit 或事件总线会变得复杂且难以维护,就像超市里每个货架(组件)都自己记录顾客的购物车内容,无法保证全局一致性。

二、Vuex核心概念图解

用超市购物车类比Vuex的工作流程:

Vuex概念超市购物车类比作用说明
State当前购物车中的实际商品唯一数据源,存储所有共享状态
Getters购物车总价计算器从state派生计算属性(如总价)
Mutations收银台修改购物车的唯一方式同步修改state(类似收据)
Actions顾客的购物行为(放入/拿出商品)异步操作,最终提交mutation
Modules按商品分类划分的购物车区域大型项目中拆分store的结构

三、手把手配置Vuex

3.1 安装与基础配置

npm install vuex@next --save  # Vue 3项目
# 或
npm install vuex@3 --save    # Vue 2项目

3.2 创建Store

// store/index.js
import { createStore } from 'vuex'

export default createStore({
  state: {
    cartItems: [],       // 购物车商品
    user: null           // 当前用户
  },
  mutations: {
    // 同步操作:添加商品到购物车
    ADD_TO_CART(state, product) {
      const existing = state.cartItems.find(item => item.id === product.id)
      existing ? existing.quantity++ : state.cartItems.push({...product, quantity: 1})
    }
  },
  actions: {
    // 异步操作:模拟从API获取用户信息
    async fetchUser({ commit }) {
      const user = await axios.get('/api/user')
      commit('SET_USER', user.data)
    }
  },
  getters: {
    // 计算购物车总价
    cartTotal: state => {
      return state.cartItems.reduce((sum, item) => sum + item.price * item.quantity, 0)
    }
  }
})

四、核心概念深度解析

4.1 State:单一数据源

原则 :所有组件共享同一份state,类似超市的中央库存系统

访问方式

<template>
  <div>购物车数量:{{ $store.state.cartItems.length }}</div>
</template>

<script>
export default {
  computed: {
    // 使用mapState辅助函数
    ...mapState(['user', 'cartItems'])
  }
}
</script>

4.2 Getters:派生状态计算

场景 :当需要基于state进行计算时(如过滤、统计)

示例 :根据用户等级显示不同价格

getters: {
  discountedPrice: (state) => (productId) => {
    const product = state.products.find(p => p.id === productId)
    return state.user.isVIP ? product.price * 0.9 : product.price
  }
}
// 组件中使用:$store.getters.discountedPrice(123)

4.3 Mutations:同步修改状态

重要规则

必须是同步函数

使用常量命名(避免拼写错误)

// mutation-types.js
export const ADD_TO_CART = 'ADD_TO_CART'

// store.js
mutations: {
  [ADD_TO_CART](state, product) { /*...*/ }
}

// 组件提交
this.$store.commit(ADD_TO_CART, product)

4.4 Actions:处理异步操作

典型场景 :API请求、定时操作

示例 :结账流程

actions: {
  async checkout({ commit, state }) {
    // 1. 显示加载状态
    commit('SET_LOADING', true)
    
    try {
      // 2. 调用支付API
      await axios.post('/api/checkout', { items: state.cartItems })
      
      // 3. 清空购物车
      commit('CLEAR_CART')
    } catch (error) {
      commit('SET_ERROR', '支付失败,请重试')
    } finally {
      commit('SET_LOADING', false)
    }
  }
}
// 组件触发:$store.dispatch('checkout')

4.5 Modules:模块化拆分

项目结构

store/
├─ index.js          # 主store文件
├─ modules/
  ├─ cart.js       # 购物车模块
  ├─ user.js       # 用户模块
  └─ products.js   # 商品模块

模块定义

// store/modules/cart.js
export default {
  namespaced: true,  // 启用命名空间
  state: () => ({
    items: []
  }),
  mutations: { /*...*/ },
  getters: {
    itemCount: state => state.items.length
  }
}

组件访问模块

computed: {
  ...mapState('cart', ['items']),
  ...mapGetters('cart', ['itemCount'])
},
methods: {
  ...mapActions('cart', ['addToCart'])
}

五、实际场景最佳实践

5.1 持久化存储

使用 vuex-persistedstate 在页面刷新时保持状态:

import createPersistedState from 'vuex-persistedstate'

export default createStore({
  plugins: [createPersistedState({
    paths: ['cart']  // 只持久化购物车数据
  })],
  // ...其他配置
})

5.2 严格模式

开发环境下开启严格模式,防止直接修改state:

export default createStore({
  strict: process.env.NODE_ENV !== 'production'
})

5.3 表单处理

当v-model绑定Vuex state时,使用计算属性的setter:

<input v-model="message">

<script>
export default {
  computed: {
    message: {
      get() { return this.$store.state.message },
      set(value) { this.$store.commit('UPDATE_MESSAGE', value) }
    }
  }
}
</script>

六、常见问题解答

Q1:Vuex与LocalStorage的区别?

VuexLocalStorage
数据性质响应式,内存存储非响应式,磁盘存储
使用场景组件间共享的临时状态需要持久化的数据(如token)
数据更新通过mutation/action更新直接读写

Q2:什么时候该用Vuex?

  • 多个视图依赖同一状态
  • 不同视图需要变更同一状态
  • 中大型项目需要可预测的状态管理

Q3:小型项目需要Vuex吗?

如果组件层级简单,可以使用:

  • provide/inject
  • 事件总线(event bus)
  • 组合式API的共享状态

七、实战代码示例

gitee官网上有很多开源项目

总结

Vuex的核心在于 规范化的状态管理流程 ,通过强制使用mutation修改状态、action处理异步,确保状态变化的可追踪性。当项目复杂度上升时,合理的模块拆分和持久化策略能让你的应用保持可维护性。

思考题

如果购物车模块需要根据不同用户显示不同商品,如何设计Vuex结构?欢迎在评论区讨论你的方案!

码字不易,各位大佬点点赞呗