3.6 修改vuex的状态Mutations ,Actions

目录

​编辑

不能直接修改state

不允许直接修改的原因

如何启用严格模式

注意事项

[如何修改 state](#如何修改 state)

Mutations

[定义 Mutations](#定义 Mutations)

[提交 Mutations](#提交 Mutations)

[使用 Vuex 在组件内提交 Mutations](#使用 Vuex 在组件内提交 Mutations)

actions

[为什么需要 Actions?](#为什么需要 Actions?)

[定义 Actions](#定义 Actions)

[分发 Actions](#分发 Actions)

[在组件中使用 Actions](#在组件中使用 Actions)

[Actions 的返回值](#Actions 的返回值)

总结


不能直接修改state

state 对象不能直接修改。这是因为 Vuex 设计的核心原则之一是状态的单一数据源和状态的不可变性(immutability)。Vuex 的 state 是响应式的,这意味着当 state 发生变化时,Vue 能够检测到这些变化并更新视图。然而,为了确保状态的变化是可追踪和预测的,Vuex 强制所有的状态变更都必须通过明确的提交(commit)来完成。

不允许直接修改的原因

  1. 响应式机制 :如果直接修改 state,Vue 的响应式系统可能无法检测到这些变化,导致视图不会正确更新。

  2. 调试和开发工具支持 :Vuex 提供了时间旅行和状态快照等功能,这些功能依赖于对状态变更的明确记录。如果可以随意修改 state,那么调试将会变得非常困难。

  3. 维护性和可读性:通过定义明确的 mutation 来改变状态,可以使代码更加清晰、易于理解和维护。

为了让直接修改 Vuex 的 state 报错,你可以利用 Vue 和 Vuex 提供的严格模式(strict mode)。在严格模式下,任何不在 mutation 函数中进行的 state 修改都会抛出错误。这有助于确保所有的状态变更都是通过明确的提交来完成的,从而增强应用的可维护性和调试能力。

如何启用严格模式

在创建 Vuex store 时,可以通过设置 strict: true 来启用严格模式:

复制代码
const store = new Vuex.Store({
  state: {
    // your state
  },
  mutations: {
    // your mutations
  },
  strict: true // 启用严格模式
})

注意事项

  1. 开发环境:严格模式会对性能有轻微影响,因为它会在每次状态变更时进行额外的检查。因此,建议只在开发环境中启用严格模式,在生产环境中应将其关闭以避免不必要的性能开销。

  2. 生产环境禁用:通常情况下,你会根据环境变量来决定是否启用严格模式。例如,可以这样做:

    复制代码
    const store = new Vuex.Store({
      state: {
        // your state
      },
      mutations: {
        // your mutations
      },
      strict: process.env.NODE_ENV !== 'production' // 根据环境变量判断
    })

通过这种方式,你可以在开发过程中捕获所有对 Vuex 状态的非法直接修改,帮助你更好地遵循 Vuex 的最佳实践,即所有的状态变更都应该通过 mutation 进行。这不仅提高了代码的可维护性,也使得调试变得更加容易。

如何修改 state

Mutations

为了修改 Vuex 中的 state,你需要使用 mutations。Mutations 是唯一能够改变 state 的方式,并且它们必须是同步函数。这意味着所有状态的变更都必须通过 mutations 来进行。这样做的好处是可以集中管理和追踪所有的状态变化,有助于调试和维护。以下是一个简单的例子:

复制代码
// 在 store 中定义 mutation
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      // 变更状态
      state.count++
    }
  }
})

// 在组件中提交 mutation
this.$store.commit('increment')

基本概念

  1. 同步性: Mutations 必须是同步函数。这意味着当你调用一个 mutation handler,这个调用完成后,状态应该已经被更新了。这使得 Vuex 能够记录每一次的状态变更,并允许开发者使用 devtools 进行时间旅行调试(time travel debugging)。

  2. Payload: 你可以向 mutations 提交额外的参数,这些参数被称为 payload(载荷)。这允许你传递需要的数据到 mutation 函数中。

  3. 提交风格: 可以使用两种方式提交 mutations:普通风格和对象风格。

定义 Mutations

在 Vuex store 中定义 mutations:

复制代码
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      // 修改状态
      state.count++
    },
    decrement(state, payload) {
      // 使用载荷来修改状态
      state.count -= payload.amount
    }
  }
})

在这个例子中,我们定义了两个 mutations: incrementdecrementincrement 不接受任何参数,而 decrement 接受一个包含 amount 属性的对象作为其载荷。

提交 Mutations

可以通过 store.commit 方法来提交 mutations。有两种提交风格:

  • 普通风格

    复制代码
    store.commit('increment')
  • 对象风格

    对象风格允许你在提交时同时指定 mutation 类型和载荷。

    复制代码
    store.commit({
      type: 'decrement',
      amount: 10
    })

对于带载荷的 mutation 调用,你也可以这样写:

复制代码
store.commit('decrement', { amount: 10 })
使用 Vuex 在组件内提交 Mutations

在 Vue 组件内部,你可以通过 this.$store.commit 来提交 mutations,或者更推荐的方式是使用 mapMutations 辅助函数将组件的方法映射为 store.commit 调用。

使用 mapMutations:

复制代码
import { mapMutations } from 'vuex'

export default {
  methods: {
    ...mapMutations([
      'increment', 
      'decrement'
    ]),
    someMethod() {
      this.increment()
      this.decrement({ amount: 5 })
    }
  }
}

这样做可以让组件的方法直接映射到对应的 mutations 上,使代码更加简洁。

Mutations 是 Vuex 中用于修改 state 的唯一合法途径,确保了所有状态的变化都是可预测和可追踪的。通过定义明确的 mutations 并遵循严格的提交规则,可以帮助开发者更好地管理应用的状态,提升代码的可读性和可维护性。

actions

如果你需要执行异步操作,应该使用 actions。Actions 可以包含任意异步操作,并且最终通过提交 mutation 来改变状态。

复制代码
// 在 store 中定义 action
const store = new Vuex.Store({
  actions: {
    incrementAsync({ commit }) {
      setTimeout(() => {
        commit('increment')
      }, 1000)
    }
  }
})

// 在组件中分发 action
this.$store.dispatch('incrementAsync')

通过这种方式,你可以确保所有状态的更改都是透明和可控的,这有助于保持应用的一致性和可维护性。

Actions 类似于 Mutations,但不同之处在于:

  • Actions 提交的是 Mutations,而不是直接变更状态
  • Actions 可以包含任意异步操作

简单来说,Actions 是处理业务逻辑(尤其是异步操作)的地方,而 Mutations 是唯一修改状态的地方


为什么需要 Actions?
  1. 处理异步操作 :Vuex 的核心原则是 Mutations 必须是同步函数。这是为了确保状态变更的可预测性,使得 Vue Devtools 可以准确地记录每一次状态变更。如果允许在 Mutations 中执行异步操作,我们就无法确切知道状态是在何时、以何种顺序发生的改变。
  2. 封装复杂逻辑:Actions 允许你在提交 Mutation 之前执行复杂的业务逻辑,比如数据验证、组合多个异步请求、条件判断等。

定义 Actions

在 Vuex store 的 actions 选项中定义 Actions。每个 Action 函数接收一个名为 context 的对象作为第一个参数。这个 context 对象包含以下属性和方法:

  • state: 指向 store.state
  • rootState: 指向根模块的 state(在模块化 store 中使用)。
  • commit: 用于提交 Mutation。
  • dispatch: 用于分发(调用)其他 Action。
  • getters: 指向 store.getters
  • rootGetters: 指向根模块的 getters(在模块化 store 中使用)。

通常,我们使用 ES2015 的参数解构语法来直接提取 commit(以及 state, getters 等),使代码更简洁。

复制代码
const store = new Vuex.Store({
  state: {
    count: 0,
    userInfo: null
  },
  mutations: {
    increment(state) {
      state.count++
    },
    setUserInfo(state, userInfo) {
      state.userInfo = userInfo
    }
  },
  actions: {
    // 基本形式:使用 context.commit
    incrementAsync(context) {
      setTimeout(() => {
        context.commit('increment') // 提交 mutation
      }, 1000)
    },

    // 使用参数解构:直接解构出 commit
    incrementAsync2({ commit }) {
      setTimeout(() => {
        commit('increment')
      }, 1000)
    },

    // 包含异步操作和复杂逻辑
    fetchUserInfo({ commit, state }) {
      // 可以检查当前状态,例如避免重复请求
      if (state.userInfo) {
        console.log('User info already exists, skipping fetch.')
        return
      }

      // 模拟异步 API 调用
      api.getUserInfo().then(userInfo => {
        commit('setUserInfo', userInfo) // 成功后提交 mutation
      }).catch(error => {
        console.error('Failed to fetch user info:', error)
        // 可以提交一个错误处理的 mutation
        // commit('setError', error.message)
      })
    },

    // 组合多个 actions (使用 dispatch)
    initializeApp({ dispatch }) {
      // 可以并行或串行地调用其他 actions
      dispatch('fetchUserInfo')
      dispatch('fetchSettings')
      // ... 其他初始化逻辑
    }
  }
})

分发 Actions

使用 store.dispatch 方法来触发(分发)Actions。与 commit 不同,dispatch 可以返回一个 Promise(如果 Action 内部返回了 Promise),这使得你可以处理异步操作的完成状态。

复制代码
// 1. 基本分发
store.dispatch('incrementAsync')

// 2. 分发时携带载荷 (Payload)
store.dispatch('fetchUserInfo', { userId: 123 }) // 载荷作为第二个参数
// 在 Action 中,可以通过第二个参数接收载荷
// actions: { fetchUserInfo({ commit }, payload) { ... } }

// 3. 使用对象风格分发
store.dispatch({
  type: 'fetchUserInfo',
  userId: 123
})

// 4. 处理返回的 Promise
store.dispatch('fetchUserInfo').then(() => {
  console.log('User info fetched successfully!')
}).catch(error => {
  console.error('Fetch failed:', error)
})

在组件中使用 Actions

在 Vue 组件中,可以通过 this.$store.dispatch 来分发 Actions,或者使用 mapActions 辅助函数。

方法一:直接使用 this.$store.dispatch

复制代码
export default {
  methods: {
    async handleFetchUser() {
      try {
        await this.$store.dispatch('fetchUserInfo')
        console.log('User loaded!')
      } catch (error) {
        console.error('Error:', error)
      }
    }
  }
}

方法二:使用 mapActions 辅助函数

复制代码
import { mapActions } from 'vuex'

export default {
  methods: {
    // 将 this.incrementAsync() 映射为 this.$store.dispatch('incrementAsync')
    ...mapActions([
      'incrementAsync',
      'fetchUserInfo'
    ]),

    // 也可以将 action 映射到不同的方法名
    ...mapActions({
      loadUser: 'fetchUserInfo' // 将 this.loadUser() 映射为 this.$store.dispatch('fetchUserInfo')
    }),

    async handleInitialize() {
      // 使用映射后的方法
      await this.loadUser()
      // 或者
      // await this.fetchUserInfo()
    }
  }
}

Actions 的返回值

Actions 可以返回任何值,但通常返回一个 Promise,以便调用者可以知道异步操作何时完成。

复制代码
actions: {
  async fetchUserInfoAsync({ commit }) {
    try {
      const userInfo = await api.getUserInfo() // 假设 api.getUserInfo 返回 Promise
      commit('setUserInfo', userInfo)
      return userInfo // 返回获取到的数据
    } catch (error) {
      console.error(error)
      throw error // 重新抛出错误,让调用者处理
    }
  }
}

// 在组件中使用
methods: {
  async loadUser() {
    try {
      const userInfo = await this.$store.dispatch('fetchUserInfoAsync')
      console.log('Fetched user:', userInfo)
    } catch (error) {
      // 处理错误
    }
  }
}

总结
  • Actions 是处理异步操作和复杂业务逻辑的中心
  • Actions 通过 context.commit 来提交 Mutations 以修改状态
  • 使用 store.dispatch (或 this.$store.dispatch / mapActions) 来触发 Actions
  • Actions 支持载荷和对象风格的分发
  • Actions 可以返回 Promise,便于处理异步流程

遵循 "Actions 处理逻辑,Mutations 修改状态" 的模式,是构建可维护、可调试的 Vuex 应用的关键。

写在最后.

能入手一个可以的项目. 框架是基础. 底层的js+html+css 也需要打牢.

博主也完结了 前端 基础课程 .参考 https://blog.csdn.net/chxii/category_12913839.html