vuex 解析 + 模拟实现

本文介绍了Vuex的核心步骤,包括集中式存储管理和状态变化的控制。并动手实现了Vuex的、和部分功能,同时提到实际的Vuex源码中还利用了Vue的计算属性缓存。建议读者深入研究源码以获得更全面的理解。
摘要由CSDN通过智能技术生成

本文将简单实现 vuex 中的 statemutationsactionsgetters

核心步骤

先简单回顾一下 vuex

vuex 集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以可预测的方式发生变化

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

// 每个组件通过 this.$store 访问仓库
Vue.use(Vuex)

export default new Vuex.store({
  // 状态应该是响应式的
  // 在组件中访问值格式是 this.$store.state.xxx
  state: {
	counter: 0
  },
  mutations: {
    add (state) {
      // state 从哪来?
      // 为什么直接对其中的数据进行操作就能响应式地改变?
      state.counter++
    }
  },
  actions: {
  	add ({ commit }) {
	  // 第一个参数是什么?从哪来的?
	  setTimeout(() => {
	  	commit('add')
	  }, 1000)
	}
  },
  getters: {
  	doubleCounter (state) {
  	  return state.counter * 2
  	}
  }
})

views/HelloWorld.vue

<template>
  <div class="hello">
	<p @click="$store.commit('add')">counter: {{$store.state.counter}}</p>
	<p @click="$store.dispatch('add')">async counter: {{$store.state.counter}}</p>
	<p>{{$store.getters.doubleCounter}}</p>
  </div>
</template>

手撸 vuex

store/index.js

import Vue from 'vue'
// import Vuex from 'vuex'
import Vuex from '../myVuex'

// 每个组件通过 this.$store 访问仓库
Vue.use(Vuex)

export default new Vuex.store({
  // 状态应该是响应式的
  // 在组件中访问值格式是 this.$store.state.xxx
  state: {
	counter: 0
  },
  mutations: {
    add (state) {
      // state 从哪来?
      // 为什么直接对其中的数据进行操作就能响应式地改变?
      state.counter++
    }
  },
  actions: {
  	add ({ commit }) {
	  // 第一个参数是什么?从哪来的?
	  setTimeout(() => {
	  	commit('add')
	  }, 1000)
	}
  },
  getters: {
  	doubleCounter (state) {
  	  return state.counter * 2
  	}
  }
})

main.js

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

myVuex/index.js

// 1.实现插件,挂载 $store
// 2.实现 Store

let Vue

// 在 store/index.js 中进行的 new 操作
class Store {
  constructor (options) {
	// 对 data 进行响应式处理
	// 这里用一个巧妙的方法,利用 new Vue({data: xxx}) 实现对传入数据的响应式绑定
	// 因为 Vue 会对它的所有数据进行响应式处理
	// 在源码中也运用了这个方法
	// 在每个组件中通过 this.$store.state.xx 访问
	this._vm = new Vue({
	  data: {
	  	$$state: options.state
	  }
	})

	// 保存用户定义的 mutations 和 actions
	this._mutations = options.mutations
	this._actions = options.actions

	// 定义 getters
	this.getters = {}
	Object.keys(options.getters).forEach((g) => {
	  Object.defineProperty(this.getters, g, {
		get: () => options.getters[g](this.state)
	  })
	})

	// 最好强绑定一下 this,特别是异步时
	this.commit = this.commit.bind(this)
	this.dispatch = this.dispatch.bind(this)
  }

  get state () {
	// 在 Vue 中,_data 可以映射到上述的 data
	// 在这里先想成是 Vue 的黑魔法完成的
	// 两个 $$ 不会被代理
	return this._vm._data.$$state
  }

  set state () {
	console.error('Please use derived state to reset state')
  }

  commit (type, payload) {
	const entry = this._mutations[type]
	if (!entry) {
	  console.error('Unknown mutation type')
	  return
	}
	// 此处解答了为什么在 mutations 中可以直接访问 state 并直接修改
	entry(this.state, payload)
  }

  dispatch (type, payload) {
  	const entry = this._actions[type]
  	if (!entry) {
  	  console.error('Unknown mutation error')
  	  return
  	}
  	entry(this, payload)
  }
}

function install (_Vue) {
  Vue = _Vue

  Vue.mixin({
	beforeCreate () {
	  // 在 main.js 中初始化根组件时会传入 store
	  if (this.$options.store) {
	    /*
		  new Vue({
		    router,
		    store.
		    render: h => h(App)
		  })
		*/
		Vue.prototype.$store = this.$options.store
	  }
	}
  })
}

// 之所以用这种形式是因为在 store 的使用形式是
// new Vuex.store({xxx})
export default { Store, install }

getters 的实现上,其实在源码中还利用了 Vue 的计算属性的缓存特性,在本文中只是简单实现了一下,还是推荐大家看一下源码

非常感谢你能看到这里!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值