Vuex使用详解(基础到进阶通关大全)

167 篇文章 3 订阅
72 篇文章 11 订阅

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它可以让我们更方便地管理应用程序的数据流,实现组件之间的通信,以及构建复杂的业务逻辑。在本文中,我将以 Vuex 的使用详解为主题,介绍 Vuex 的基本用法和高级用法,以及一些常见的问题和解决方案。本文假设你已经对 Vue.js 有一定的了解。

安装

公众号:Code程序人生,个人网站:https://creatorblog.cn

直接下载/CDN引用

https://unpkg.com/vuex@4

Unpkg.com 提供了基于 npm 的 CDN 链接。以上的链接会一直指向 npm 上发布的最新版本。您也可以通过 https://unpkg.com/vuex@4.0.0/dist/vuex.global.js 这样的方式指定特定的版本。

npm

npm install vuex@next --save

yarn

yarn add vuex@next --save

自己构建

如果需要使用 dev 分支下的最新版本,您可以直接从 GitHub 上克隆代码并自己构建。

git clone https://github.com/vuejs/vuex.git node_modules/vuex
cd node_modules/vuex
yarn
yarn build

基本用法

Vuex 的核心概念是statemutationactiongetter

  • state是存储在 Vuex 中的数据,它是响应式的,也就是说当状态发生变化时,依赖于状态的组件也会自动更新。

  • mutation是唯一能够改变状态的方法,它是同步的,并且每次突变都会被记录下来,方便调试和追踪。

  • action是异步的操作,它可以包含任意的逻辑和副作用,并且通过提交突变来改变状态。

  • getter是对状态的派生或计算属性,它可以让我们更方便地获取和处理状态。

创建store实例

要使用 Vuex,我们首先需要创建一个存储器(store)实例,并将其注册到根组件中:

// 创建一个 store 实例
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++
    }
  },
  actions: {
    incrementAsync({ commit }) {
      setTimeout(() => {
        commit('increment')
      }, 1000)
    }
  },
  getters: {
    doubleCount(state) {
      return state.count * 2
    }
  }
})

new Vue({
  el: '#app',
  store,
  // ...
})

注册了 store 之后,我们就可以在组件中通过 this.$store 访问 store 实例,并通过以下几种方式使用 Vuex

使用mapState

使用 mapState 辅助函数来将状态映射到组件的计算属性中:

import { mapState } from 'vuex'

export default {
  computed: {
    ...mapState({
      count: state => state.count,
      countAlias: 'count',
      countPlusLocalState (state) {
        return state.count + this.localCount
      }
    })
  }
}

使用mapMutations

使用 mapMutations 辅助函数来将突变映射到组件的方法中:

import { mapMutations } from 'vuex'

export default {
  methods: {
    ...mapMutations([
      'increment',
      'incrementBy'
    ]),
    ...mapMutations({
      add: 'increment'
    })
  }
}

使用mapActions

使用 mapActions 辅助函数来将动作映射到组件的方法中:

import { mapActions } from 'vuex'

export default {
  methods: {
    ...mapActions([
      'increment',
      'incrementBy'
    ]),
    ...mapActions({
      add: 'increment'
    })
  }
}

使用mapGetters

使用 mapGetters 辅助函数来将获取器映射到组件的计算属性中:

import { mapGetters } from 'vuex'

export default {
  computed: {
    ...mapGetters([
      'doubleCount',
      'anotherGetter'
    ])
  }
}

进阶用法

Vuex 还提供了一些高级用法,让我们可以更灵活和高效地使用 Vuex。这些高级用法包括:

  • 模块module):Vuex 允许我们将 store 分割成多个模块,每个模块拥有自己的statemutationactiongetter。这样可以让我们更好地组织和管理复杂的状态。例如:
// 创建一个模块 a
const moduleA = {
  state: () => ({
    count: 0
  }),
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    incrementIfOdd ({ state, commit }) {
      if (state.count % 2 === 1) {
        commit('increment')
      }
    }
  },
  getters: {
    doubleCount (state) {
      return state.count * 2
    }
  }
}

// 创建一个模块 b
const moduleB = {
  state: () => ({
    name: 'Alice'
  }),
  mutations: {
    changeName (state, newName) {
      state.name = newName
    }
  },
  actions: {
    changeNameAsync ({ commit }, newName) {
      setTimeout(() => {
        commit('changeName', newName)
      }, 1000)
    }
  },
  getters: {
    nameLength (state) {
      return state.name.length
    }
  }
}

然后,我们可以在创建 store 实例时,通过 modules 选项来注册模块:

// 创建一个 store 实例
const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

这样,我们就可以通过 store.state.astore.state.b 来访问模块 a 和模块 b 的状态。

同样,我们也可以通过 store.commit('a/increment')store.commit('b/changeName', 'Bob') 来提交模块 a 和模块 bmutationactiongetter也是类似的,只需要在前面加上模块的命名空间即可。

如果我们想要让模块的动作和获取器不受命名空间的限制,我们可以在注册模块时,通过 namespaced: false 来关闭命名空间。

这样,我们就可以直接使用 store.dispatch('incrementIfOdd')store.getters['doubleCount'] 来调用模块 aactiongetter

但是,这样做可能会导致命名冲突的问题,所以建议使用命名空间来避免混淆。

Vuex 还提供了一些辅助函数来简化模块化的使用。例如:

  • 使用 createNamespacedHelpers 函数来创建一个带有命名空间的辅助函数集合:
import { createNamespacedHelpers } from 'vuex'

const { mapState, mapActions, mapGetters, mapMutations } = createNamespacedHelpers('some/nested/module')

export default {
  computed: {
    // 在 `some/nested/module` 中查找
    ...mapState({
      a: state => state.a
    }),
    ...mapGetters({
      b: 'b'
    })
  },
  methods: {
    // 在 `some/nested/module` 中查找
    ...mapActions([
      'foo'
    ]),
    ...mapMutations({
      bar: 'bar'
    })
  }
}
  • 使用 createLogger 插件来打印每次突变的日志:
import createLogger from 'vuex/dist/logger'

const store = new Vuex.Store({
  plugins: [createLogger()]
})
  • 使用 createPersistedState 插件来将状态持久化到本地存储中:
import createPersistedState from 'vuex-persistedstate'

const store = new Vuex.Store({
  plugins: [createPersistedState()]
})

常见问题和解决方案

Vuex 的使用可能会遇到一些常见的问题和困难,这里列举了一些常见问题和解决方案,希望对你有所帮助。

如何在组件外部访问 store

有时候,我们可能需要在组件外部访问 store,例如在路由钩子函数或者 API 请求中。这时候,我们可以通过导出 store 实例,并在需要的地方导入它来实现。例如:

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

Vue.use(Vuex)

export const store = new Vuex.Store({
  // ...
})

// router.js
import { store } from './store'

router.beforeEach((to, from, next) => {
  // 访问 store
  if (store.state.user) {
    next()
  } else {
    next('/login')
  }
})

// api.js
import { store } from './store'
import axios from 'axios'

export function getUserInfo () {
  // 访问 store
  const token = store.state.token
  return axios.get('/user/info', {
    headers: {
      Authorization: `Bearer ${token}`
    }
  })
}

如何在mutation中执行异步操作

Vuexmutation是同步的,也就是说,我们不能在mutation中执行异步操作,例如 setTimeoutfetchaxios 等。

如果我们需要执行异步操作,我们应该在action中执行,并在异步操作完成后,提交mutation来改变state。例如:

// 错误的做法:在突变中执行异步操作
mutations: {
  incrementAsync (state) {
    setTimeout(() => {
      state.count++
    }, 1000)
  }
}

// 正确的做法:在动作中执行异步操作,并提交突变
actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

如何处理多个action的组合

有时候,我们可能需要将多个action组合起来,形成一个复杂的业务逻辑。这时候,我们可以使用 Promise 或者 async/await 来处理异步流程。例如:

actions: {
  // 使用 Promise
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      // 异步操作
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  },
  // 使用 async/await
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成
    commit('anotherMutation')
  }
}

如何处理表单的双向绑定

Vuex 的状态是响应式的,也就是说,当state发生变化时,依赖于state的组件也会自动更新。

但是,这并不意味着我们可以直接在组件中修改state,因为这样会破坏 Vuex 的状态管理模式。

如果我们想要实现表单的双向绑定,我们有以下几种方法:

  • 使用 v-model 的修饰符 .lazy,并在 inputchange 事件中提交mutation
<input v-model.lazy="message" @change="updateMessage">
computed: {
  message: {
    get () {
      return this.$store.state.message
    },
    set (value) {
      this.updateMessage(value)
    }
  }
},
methods: {
  updateMessage (value) {
    this.$store.commit('updateMessage', value)
  }
}
  • 使用 v-model 的修饰符 .number.trim,并在 inputchange 事件中提交mutation
<input v-model.number="age" type="number" @input="updateAge">
<input v-model.trim="name" @input="updateName">
computed: {
  age: {
    get () {
      return this.$store.state.age
    },
    set (value) {
      this.updateAge(value)
    }
  },
  name: {
    get () {
      return this.$store.state.name
    },
    set (value) {
      this.updateName(value)
    }
  }
},
methods: {
  updateAge (value) {
    this.$store.commit('updateAge', value)
  },
  updateName (value) {
    this.$store.commit('updateName', value)
  }
}
  • 使用 computed 属性的 getset 方法,并在 set 方法中提交mutation
<input v-model="message">
computed: {
  message: {
    get () {
      return this.$store.state.message
    },
    set (value) {
      this.$store.commit('updateMessage', value)
    }
  }
}

总结

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它可以让我们更方便地管理应用程序的数据流,实现组件之间的通信,以及构建复杂的业务逻辑。

Vuex 的核心概念是statemutationactiongettermoduleVuex 还提供了一些进阶用法,让我们可以更灵活和高效地使用 VuexVuex 的使用可能会遇到一些常见的问题和困难,文中列举了一些常见问题和解决方案。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CreatorRay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值