Vuex Store实例中`state`、`mutations`、`actions`、`getters`、`modules`这几个核心配置项的区别

bash 复制代码
// 创建store实例
const store = new Vuex.Store({
  state: {
    // ...
  },
  mutations: {
    // ...
  },
  actions: {
    // ...
  },
  getters: {
    // ...
  },
  modules: {
    // ...
  }
})

// 在app.js中注入store
App({
  onLaunch: function () {
    this.$store = store
  }
}) store实例几个方法有什么区别,用法怎么区分

这些配置项是Vuex实现全局状态管理的核心,各自承担明确的职责,下面我会用通俗易懂的方式讲解每个项的作用、特点和用法,并对比它们的核心区别。


1. state - 全局状态的"仓库"

核心作用

存放整个应用的全局共享数据 ,类似Vue组件中的data,但作用域是全局的(所有组件都能访问)。

核心特点

  • 响应式:state数据变化时,依赖它的组件会自动更新
  • 规范要求:不能直接修改 (直接修改会跳过Vuex的状态追踪,调试工具无法监控),必须通过mutations修改

用法示例

javascript 复制代码
const store = new Vuex.Store({
  state: {
    count: 0,       // 全局计数
    userInfo: null  // 全局用户信息
  }
})

// 组件中获取state的两种方式
// 方式1:直接通过$store访问
this.$store.state.count // 输出 0

// 方式2:mapState辅助函数(推荐,简化代码)
import { mapState } from 'vuex'
export default {
  computed: {
    // 把state中的count、userInfo映射为组件的计算属性
    ...mapState(['count', 'userInfo'])
  }
}

2. mutations - 修改state的"唯一入口"

核心作用

唯一能修改state的地方 ,负责同步更新state数据。

核心特点

  • 必须是同步函数(异步操作会导致Vuex调试工具无法追踪状态变化)
  • 只能通过store.commit()触发,不能直接调用mutation函数

用法示例

javascript 复制代码
const store = new Vuex.Store({
  state: { count: 0 },
  mutations: {
    // 定义mutation:第一个参数固定是state,第二个是载荷(payload,传入的参数)
    increment(state) {
      state.count++ // 直接修改state(仅允许在mutation中做这件事)
    },
    // 带参数的mutation
    incrementBy(state, num) {
      state.count += num
    }
  }
})

// 组件中触发mutation的两种方式
// 方式1:直接commit
this.$store.commit('increment')       // count变为1
this.$store.commit('incrementBy', 5)  // count变为6

// 方式2:mapMutations辅助函数
import { mapMutations } from 'vuex'
export default {
  methods: {
    ...mapMutations(['increment', 'incrementBy']),
    handleClick() {
      this.increment()        // 直接调用
      this.incrementBy(5)     // 传参调用
    }
  }
}

3. actions - 处理异步逻辑的"中间层"

核心作用

处理异步操作 (比如接口请求、定时器、Promise),异步操作完成后,再提交mutation修改state。

核心特点

  • 可以是异步函数(支持async/await)
  • 不能直接修改state,必须通过commit调用mutation
  • 第一个参数是context(上下文对象,包含commit/state/getters等)
  • 通过store.dispatch()触发

用法示例

javascript 复制代码
const store = new Vuex.Store({
  state: { count: 0 },
  mutations: {
    increment(state) { state.count++ }
  },
  actions: {
    // 异步action:模拟接口请求后修改count
    incrementAsync(context) {
      // 异步操作(比如定时器/接口请求)
      setTimeout(() => {
        context.commit('increment') // 异步完成后,提交mutation
      }, 1000)
    },
    // 简化写法:解构context,直接用commit
    incrementAsyncBy({ commit }, num) {
      return new Promise((resolve) => {
        setTimeout(() => {
          commit('incrementBy', num)
          resolve() // 支持Promise链式调用
        }, 1000)
      })
    }
  }
})

// 组件中触发action的两种方式
// 方式1:直接dispatch
this.$store.dispatch('incrementAsync') // 1秒后count+1

// 方式2:mapActions辅助函数
import { mapActions } from 'vuex'
export default {
  methods: {
    ...mapActions(['incrementAsync', 'incrementAsyncBy']),
    handleAsyncClick() {
      this.incrementAsync()
      this.incrementAsyncBy(5).then(() => {
        console.log('异步操作完成')
      })
    }
  }
}

4. getters - 对state数据的"计算/过滤"

核心作用

类似Vue组件中的computed,对state中的数据进行派生、过滤、计算,并缓存结果(只有依赖的state变化时才重新计算)。

核心特点

  • 基于state派生,不修改原state
  • 支持接收其他getters作为第二个参数
  • 可以返回函数,实现"带参数的getter"

用法示例

javascript 复制代码
const store = new Vuex.Store({
  state: {
    list: [1, 2, 3, 4, 5, 6]
  },
  getters: {
    // 过滤偶数
    evenList: (state) => state.list.filter(item => item % 2 === 0), // [2,4,6]
    // 依赖其他getters
    evenListLength: (state, getters) => getters.evenList.length,    // 3
    // 带参数的getter(返回函数)
    getNumById: (state) => (id) => state.list.find(item => item === id)
  }
})

// 组件中使用getters的两种方式
// 方式1:直接通过$store.getters访问
this.$store.getters.evenList       // [2,4,6]
this.$store.getters.getNumById(3)  // 3

// 方式2:mapGetters辅助函数
import { mapGetters } from 'vuex'
export default {
  computed: {
    ...mapGetters(['evenList', 'evenListLength']),
    // 重命名(避免冲突)
    ...mapGetters({ listLen: 'evenListLength' })
  }
}

5. modules - 拆分复杂store的"模块化工具"

核心作用

当应用规模大时,state/mutations/actions会变得臃肿,modules可以将store拆分为多个独立模块,每个模块拥有自己的state/mutations/actions/getters

核心特点

  • 模块内的state是局部的,需通过store.state.模块名访问
  • 默认情况下,模块内的mutations/actions是全局的(可通过namespaced: true开启命名空间,避免冲突)

用法示例

javascript 复制代码
// 定义user模块(开启命名空间)
const userModule = {
  namespaced: true, // 开启命名空间,避免和其他模块冲突
  state: { name: '张三', age: 20 },
  mutations: {
    updateName(state, newName) { state.name = newName }
  },
  actions: {
    updateNameAsync({ commit }, newName) {
      setTimeout(() => commit('updateName', newName), 1000)
    }
  }
}

// 创建store,注册模块
const store = new Vuex.Store({
  modules: {
    user: userModule, // 注册user模块
    count: { /* 另一个模块 */ }
  }
})

// 组件中使用模块内容
// 1. 获取模块state
this.$store.state.user.name // 张三

// 2. 触发带命名空间的mutation/action
this.$store.commit('user/updateName', '李四') // 格式:模块名/mutation名
this.$store.dispatch('user/updateNameAsync', '王五')

// 3. map辅助函数(指定命名空间)
import { mapMutations } from 'vuex'
export default {
  methods: {
    ...mapMutations('user', ['updateName']) // 绑定user模块的updateName
  }
}

关键点回顾

  1. 核心职责划分state存数据、mutations同步改数据(唯一入口)、actions处理异步后调mutationsgetters计算派生数据、modules拆分复杂store。
  2. 核心规则 :修改state必须通过mutations,异步逻辑必须写在actions里,禁止直接修改state
  3. 模块化技巧 :复杂应用一定要给模块加namespaced: true,避免mutation/action命名冲突,便于维护。
相关推荐
码途潇潇4 小时前
JavaScript有哪些数据类型?如何判断一个变量的数据类型?
前端·javascript
满天星辰4 小时前
Vue真的是单向数据流?
前端·vue.js
细心细心再细心4 小时前
Nice-modal-react的使用
前端
我的写法有点潮4 小时前
JS中对象是怎么运算的呢
前端·javascript·面试
悠哉摸鱼大王4 小时前
NV12 转 RGB 完整指南
前端·javascript
一壶纱4 小时前
UniApp + Pinia 数据持久化
前端·数据库·uni-app
双向334 小时前
【RAG+LLM实战指南】如何用检索增强生成破解AI幻觉难题?
前端
海云前端14 小时前
前端人必懂的浏览器指纹:不止是技术,更是求职加分项
前端
青莲8434 小时前
Java内存模型(JMM)与JVM内存区域完整详解
android·前端·面试
boooooooom4 小时前
深入浅出 Vue3 defineModel:极简实现组件双向绑定
vue.js