How to write a simple Vuex by hand
- 2021-08-28 19:20:39
- OfStack
Preface
This article is suitable for people who have used Vuex to read and understand how to implement an Vuex by themselves.
Basic skeleton
This is the src/store/index. js file of this project. Look at the use of vuex
import Vue from 'vue'
import Vuex from './myvuex' // Introduce your own writing vuex
import * as getters from './getters'
import * as actions from './actions'
import state from './state'
import mutations from './mutations'
Vue.use(Vuex) // Vue.use(plugin) Method uses vuex Plug-ins
// vuex Export 1 A class is called Store And pass in an object as a parameter
export default new Vuex.Store({
state,
mutations,
actions,
getters,
})
Vue.use
Usage of:
This method needs to be called before calling new Vue (). When the install method is called multiple times by the same plug-in, the plug-in will only be installed once.Install the Vue. js plug-in. If the plug-in is a 1 object, the install method must be provided. If the plug-in is a function, it will be used as an install method. When the install method is called, Vue is passed in as a parameter. The first parameter of this method is the Vue constructor, and the second parameter is an optional option object.
That is, we need to
./myvuex.js
Export in
install
Method, exporting 1 class at the same time
Store
So step 1 can write the code:
let Vue = null
class Store {
constructor(options) {}
}
function install(_Vue) {
Vue = _Vue // Above Store Class needs to be able to get the Vue
}
export default {
Store,
install,
}
install method
When we use vuex, each component has an this. $store attribute, which contains state, mutations, actions, getters, etc. Therefore, we also need to mount an $store attribute on each component, so that every component can get it. Here we use Vue. mixin (mixin), and the usage is introduced as follows:
Global registration of 1 mixed, affecting all Vue instances created after registration. You can use blending to inject custom behavior into the component, which affects every Vue instance created later.
function install(_Vue) {
Vue = _Vue // install Method is called, the Vue Pass in as a parameter (above Store Class requires the Vue )
// Achieve every 1 Components, all of which can pass this Call $store
Vue.mixin({
beforeCreate() {
// Pass this.$options Can get new Vue({ Parameter }) Parameters passed
if (this.$options && this.$options.store) {
// Prove this this Is the root instance, which is new Vue The instance generated
this.$store = this.$options.store
} else if (this.$parent && this.$parent.$store) {
// Child component gets the parent component's $store Attribute
this.$store = this.$parent.$store
}
},
})
}
state
Since Vuex is based on the responsive principle of Vue, we need to create an instance of vue to make the data change to the refreshable view
class Store {
// options That is Vuex.Store({}) Parameters passed in
constructor(options) {
// vuex The core is to borrow vue Because of the instance of vue The view is refreshed when the instance data of the
let vm = new Vue({
data: {
state: options.state,
},
})
// state
this.state = vm.state
}
}
commit
When we use vuex to change data, we trigger the commit method, which is used as follows:
this. $store. commit ('eventName', 'Parameters');
So we want to implement an commit method and process the mutations passed in by the Store constructor
class Store {
constructor(options) {
// Realization state ...
// mutations
this.mutations = {} // Store incoming mutations
let mutations = options.mutations || {}
// Loop out the event name for processing ( mutations[ Event name ]: Execution method)
Object.keys(mutations).forEach(key => {
this.mutations[key] = params => {
mutations[key].call(this, this.state, params) // Amendment this Point
}
})
}
commit = (key, params) => {
// key Is the name of the event to fire
this.mutations[key](params)
}
}
dispatch
Same as the commit process above
class Store {
constructor(options = {}) {
// ...
// actions
this.actions = {}
let actions = options.actions || {}
Object.keys(actions).forEach(key => {
this.actions[key] = params => {
actions[key].call(this, this, params)
}
})
}
dispatch = (type, payload) => {
this.actions[type](payload)
}
}
getters
getters actually returns the value of state, which is placed in the computed attribute when used, and every getter is in the form of a function;
getters requires bidirectional binding. But you don't need to bind all getters bidirectionally, just bind the getters used by events in your project.
The Object. defineProperty () method is used here, which either defines a new property on an object directly, or modifies an existing property on an object and returns the object.
class Store {
constructor(options = {}) {
// ...
// getters
this.getters = {}
let getters = options.getters || {}
Object.keys(getters).forEach(key => {
Object.defineProperty(this.getters, key, {
get: () => {
return getters[key].call(this, this.state)
},
})
})
}
}
So far, we can do some basic operations with our own vuex, but we can only call it in the form of this. $store. xx, so we need to implement the method again.
map auxiliary function
Let's talk about mapState first
This is used before there is no map helper function:
computed: {
count () {
return this.$store.state.count
}
}
Pass an array of strings to mapState when the name of the mapped evaluated attribute is the same as the child node name of state.
computed: {
// Use the object expansion operator to mix this object into an external object
...mapState(['count'])
}
We simply implement the array case here
export const mapState = args => {
let obj = {}
args.forEach(item => {
obj[item] = function() {
return this.$store.state[item]
}
})
return obj
}
The next few map helper functions are similar
mapGetters
let Vue = null
class Store {
constructor(options) {}
}
function install(_Vue) {
Vue = _Vue // Above Store Class needs to be able to get the Vue
}
export default {
Store,
install,
}
0
mapMutations
let Vue = null
class Store {
constructor(options) {}
}
function install(_Vue) {
Vue = _Vue // Above Store Class needs to be able to get the Vue
}
export default {
Store,
install,
}
1
mapActions
let Vue = null
class Store {
constructor(options) {}
}
function install(_Vue) {
Vue = _Vue // Above Store Class needs to be able to get the Vue
}
export default {
Store,
install,
}
2
Complete code
let Vue = null
class Store {
constructor(options) {
// vuex The core is to borrow vue Because of the instance of vue The view is refreshed when the instance data of the
let vm = new Vue({
data: {
state: options.state,
},
})
// state
this.state = vm.state
// mutations
this.mutations = {} // Store incoming mutations
let mutations = options.mutations || {}
Object.keys(mutations).forEach(key => {
this.mutations[key] = params => {
mutations[key].call(this, this.state, params)
}
})
// actions
this.actions = {}
let actions = options.actions || {}
Object.keys(actions).forEach(key => {
this.actions[key] = params => {
actions[key].call(this, this, params)
}
})
// getters
this.getters = {}
let getters = options.getters || {}
Object.keys(getters).forEach(key => {
Object.defineProperty(this.getters, key, {
get: () => {
return getters[key].call(this, this.state)
},
})
})
}
commit = (key, params) => {
this.mutations[key](params)
}
dispatch = (type, payload) => {
this.actions[type](payload)
}
}
export const mapState = args => {
let obj = {}
args.forEach(item => {
obj[item] = function() {
return this.$store.state[item]
}
})
return obj
}
export const mapGetters = args => {
let obj = {}
args.forEach(item => {
obj[item] = function() {
return this.$store.getters[item]
}
})
return obj
}
export const mapMutations = args => {
let obj = {}
args.forEach(item => {
obj[item] = function(params) {
return this.$store.commit(item, params)
}
})
return obj
}
export const mapActions = args => {
let obj = {}
args.forEach(item => {
obj[item] = function(payload) {
return this.$store.dispatch(item, payload)
}
})
return obj
}
function install(_Vue) {
Vue = _Vue // install Method is called, the Vue Pass in as a parameter (above Store Class requires the Vue )
// Achieve every 1 Components, all of which can pass this Call $store
Vue.mixin({
beforeCreate() {
// Pass this.$options Can get new Vue({ Parameter }) Parameters passed
if (this.$options && this.$options.store) {
// Prove this this Is the root instance, which is new Vue The instance generated
this.$store = this.$options.store
} else if (this.$parent && this.$parent.$store) {
// Child component gets the parent component's $store Attribute
this.$store = this.$parent.$store
}
},
})
}
export default {
Store,
install,
}
The above is how to handwrite a simple Vuex details, more about handwritten vuex information please pay attention to this site other related articles!