Vuex 4源码学习笔记 - Vuex是怎么与Vue结合?(三)

在上一篇笔记中:Vuex源码学习笔记 - Vuex开发运行流程(二)

我们通过运行npm run dev命令来启动webpack,来开发Vuex,并在Vuex的createStore函数中添加了第一个断点。

那么在看源码之前,建议先要熟悉Vuex的使用,如果还不熟练使用,那么在看的时候很容易会发蒙。

我们来复习下Vuex中的几个重要概念和使用

  • State - 存储状态
  • Getter - 类似计算属性
  • Mutation - 更改状态的唯一方法是提交 mutation。
  • Action - 可以包含任意异步操作,并且提交 mutation来更改状态。
  • Module - 用来分割模块,每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。

下面是计数器应用的Vuex代码

import { createStore } from 'vuex'

const state = {
  count: 0
}

const mutations = {
  increment (state) {
    state.count++
  },
  decrement (state) {
    state.count--
  }
}

const actions = {
  increment: ({ commit }) => commit('increment'),
  decrement: ({ commit }) => commit('decrement'),
  incrementIfOdd ({ commit, state }) {
    if ((state.count + 1) % 2 === 0) {
      commit('increment')
    }
  },
  incrementAsync ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('increment')
        resolve()
      }, 1000)
    })
  }
}

const getters = {
  evenOrOdd: state => state.count % 2 === 0 ? 'even' : 'odd'
}

export default createStore({
  state,
  getters,
  actions,
  mutations
})

在上面的代码中,分别创建了state、mutations、actions、getters,没有module,默认为根。

那么我们在回忆,为什么要使用Vuex呢?它解决了什么问题?

在使用Vue来开发页面或者组件时,我们在每个data函数内定义当前组件所需的状态,那么随着应用月来越大、越来越复杂,经常会遇到多个页面或组件需要共用某个状态,在一开始我们可以用组件间的通信去解决数据的同步问题。但当应用越来越大,组件越来越多,这种方式的弊病也显露出来,过于耦合,并且难以维护,当有新组件需要共享状态时,还有额外的添加代码。

那么基于这个问题思考,我们为什么不可以将Vue中data函数内的状态放在一个地方,然后多个组件都去这同一个地方去操作状态呢。

这就是Vuex。

下面这张图表示了Vuex的工作流程:

vuex

首先在左边的绿色的组件中我们可以使用Vuex中State存储的状态;

然后在组件中可以通过Dispatch触发Actions,在Actions中我们可以调用后端的服务,或者其他的异步或同步操作;

然后在Actions中会触发Mutations来修改State中的状态,

由于State是响应式的,State状态被修改,组件的视图也会随之更新;

因为只能使用Mutations来修改状态,所以State状态是可被预测的,我们可以通过Devtools来监测到状态的改变。

Vuex的使用

首先在store.js中通过createStore函数来创建vuex的实例对象

import { createStore } from 'vuex'

export default createStore({
  state: { /**...**/ },
  getters: { /**...**/ },
  actions: { /**...**/ },
  mutations: { /**...**/ }
})

然后在app.js,通过app.use函数来将vuex的实例注入到vue中

import { createApp } from 'vue'
import Counter from './Counter.vue'
import store from './store'

const app = createApp(Counter)

app.use(store)

app.mount('#app')

接着就可以在页面中去使用store了

<script>
import { computed } from 'vue'
import { useStore } from 'vuex'

export default {
  setup () {
    const store = useStore()

    return {
      count: computed(() => store.state.count),
      evenOrOdd: computed(() => store.getters.evenOrOdd),
      increment: () => store.dispatch('increment'),
      decrement: () => store.dispatch('decrement'),
      incrementIfOdd: () => store.dispatch('incrementIfOdd'),
      incrementAsync: () => store.dispatch('incrementAsync')
    }
  }
}
</script>

我们前面的文章讲过:如何编写Vue插件

使用app.use函数时,如果参数为一个对象那么Vue会自动调用函数内的install方法。

也就是src/store.js中的

import { storeKey } from './injectKey'
import { addDevtools } from './plugins/devtool'

export class Store {
  constructor (options = {}) {
   //...
  }

  install (app, injectKey) {

    // 第一,将Store对象注入到vue的实例上
    app.provide(injectKey || storeKey, this)
    app.config.globalProperties.$store = this

    // 第二,判断是否添加Vue devtool插件
    const useDevtools = this._devtools !== undefined
      ? this._devtools
      : __DEV__ || __VUE_PROD_DEVTOOLS__

    if (useDevtools) {
      addDevtools(app, this)
    }
  }

  //...
}

可以看到install函数做的事情很简单:

  • 第一,将Store对象注入到vue的实例上
  • 第二,判断是否添加Vue devtool插件

可以看到有两行代码挂载Store对象,通过provide的方式,主要是使用在setup方式中,通过useStore()来获取store

<script>
import { useStore } from 'vuex'

export default {
  setup () {
    const store = useStore()
  }
}
</script>

useStore函数的源代码在injectKey.js文件中:

import { inject } from 'vue'

export const storeKey = 'store'

export function useStore (key = null) {
  return inject(key !== null ? key : storeKey)
}

provide/inject的使用就不多讲了,更多请查看文档

第二种通过app.config.globalProperties.$store = this的方式挂载到全局vue实例中,主要是使用在下面的场景,通过this.$store来获取store的实例。

methods: {
  increment() {
    this.$store.commit('increment')
    console.log(this.$store.state.count)
  }
}

总结

今天我们复习了Vuex的使用,以及为什么要使用Vuex,同时看到了Vuex是如何与Vue去结合到一起的。

Vuex通过Vue插件的方式,通过use函数讲Vuex实例对象绑定到Vue中。

可以通过useStore函数或者this.$store两种方式在页面中访问store。

明天我们来分析Store类的构造函数都做了哪些事情。

一起学习更多前端知识,微信搜索【小帅的编程笔记】,每天更新

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值