1, the preface
This article will take you step by step to realize the main functions of Vuex. Before reading this article, you should have a basic understanding of the use of VUE and understand the basic concepts of Class.
So let’s get started
Final code link
Making a link
2. Prepare test data
We can use VueCli to build a Vuex project. Here’s a brief description of commands
# If you use YARN
yarn global add @vue/cll
# If you use NPM
npm install -g @vue/cli
Create a Vue2 project
vue create vue-study
Copy the code
After the installation, start the service directly
cd vue-study
yarn serve
Copy the code
Next we can run a test example using the official Vuex
yarn add vuex
Copy the code
Write the file store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
name: 'layouwen'.age: 100,},mutations: {
changeName(state, newName) {
state.name = newName
},
changeAge(state, newAge) {
state.age = newAge
},
},
actions: {
changeAge(store, newAge) {
setTimeout(() = > {
store.commit('changeAge', newAge)
}, 2000)}},getters: {
info(state) {
return 'my name is' + state.name + 'This year' + state.age
},
},
})
Copy the code
Edit main.js to add store to the Vue option
import store from './store'
// ...
new Vue({
store,
render: h= > h(App),
}).$mount('#app')
Copy the code
Display our data in app.vue
<template> <div id="app"> {{ $store.state.name }}</span> <button @click="$store.commit('changeName', </button> </div> <span> {{ $store.state.age }}</span> <button @click="$store.dispatch('changeAge', 21)"> commit changeName </button> </div> <div>{{$store.getters.info}}</div> </div> </template> // ...Copy the code
Now we can see our data
Now I’ll start implementing my own Vuex plug-in
3. Implement plug-in registration
When we use Vuex, we register through use, indicating that Vuex is a plug-in. An install method needs to be implemented
Create a new file to implement our own Vuex
Create a Store class, write an Install method, define a variable to hold Vue, and write dummy data in this,
src/avuex.js
// 用于保存 Vue
let Vue
// Core code
class Store {
constructor() {
this.state = {
name: 'layouwen'.age: 100,}this.getters = {
info: 'I am' + this.state.name + 'This year' + this.state.age,
}
}
}
// Register the plug-in
function install(_Vue) {
Vue = _Vue
Vue.mixin({
beforeCreate() {
if (this.$options.store) Vue.prototype.$store = this.$options.store
},
})
}
export default { Store, install }
Copy the code
Use our own **avuex.js in store/index.js
// import Vuex from 'vuex'
import Vuex from '.. /avuex'
Copy the code
Go back to the page and see if it displays properly. If successful, the plug-in is registered successfully
When vue. use(Vuex) is used, Vue automatically calls the install scheme. Using mixins, we mount our store instance in the Vue option to the prototype and we can use it in the Vue instance with this.$store
4. Implement state
When we pass in our initialization data when we new store in store/index, we need to mount this data to the Store instance
avuex.js
class Store {
constructor(options) {
this.state = options.state
this.$mutations = options.mutations
this.$actions = options.actions
this.getters = options.getters
}
}
Copy the code
Now it turns out that there is something wrong with the data displayed on our page. The reason is that our getter is a calculated property and should return the result of the function. There are several options, such as using Vue utility functions, vue.util.definereactive, or simply creating a reactive data using New Vue. We use the latter here.
class Store {
constructor(options) {
this._vm = new Vue({
data() {
return {
$$state: options.state,
}
},
})
this.$mutations = options.mutations
this.$actions = options.actions
this.getters = options.getters
}
get state() {
return this._vm.$data.$$state
}
}
Copy the code
Now go back to the page and find that it is displaying normally
Create a responsive object with new Vue and copy it to _VM followed by get when this.state is used. We get data for _vm.$data.$$state, which is the reactive state we created with new Vue
5. Implement commit
In Vuex, we modify the data by using this. codestore.com MIT (‘mutations ‘, the data required). So we need to implement a commit method in the Store instance
commit(type, payload) {
const entry = this.$mutations[type]
if(! entry) {console.error('mutation does not exist')
return
}
entry(this.state, payload)
}
Copy the code
Return to page. At this point we can modify the state.name page with commit changeName and respond to the change
So when you call commit, you’re going to pass in the parameters type and payload and use type to find out if there’s a corresponding function for mutations that we uploaded in the new Store and pass in the state and payload
6. Implement Dispatch
In general, data is modified using COMMIT during synchronization, and code is written into actions during asynchronous operations. Use Dispatch to modify. So we now implement a Dispatch to use the methods in Actions. The implementation method is the same as commit.
dispatch(type, payload) {
const entry = this.$actions[type]
if(! entry) {console.error('action does not exist')
return
}
entry(this, payload)
}
Copy the code
Back on the page at this point, we can also use dispatch changeAge normally
The implementation principle is the same as that of commit. In the action parameter acceptance, the first parameter is the store instance, so we need to pass this
Bind this to commit and Dispatch
In the normal use of commit and dispatch, it is inevitable that the this pointer will be lost. For the convenience of users. We bind this to the Store instance in the Store constructor
class Store {
constructor(options) {
// ...
this.commit = this.commit.bind(this)
this.dispatch = this.dispatch.bind(this)}Copy the code
8. Implement getters
We can borrow the computed property on the Vue instance to implement the getter, and use Object.defineProperty to implement the computed property in our Vue instance when we access this.$store.getter. So we have to map the getters option to a new computed variable to receive, because computed functions can’t take arguments, so we return the result of our getters function with a higher-order function. Assign this computed variable to computed in the Vue instance.
class Store {
constructor(options) {
this.getters = {}
this._wrapperGetters = options.getters
const computed = {}
Object.keys(this._wrapperGetters).forEach(key= > {
const store = this
computed[key] = function() {
return store._wrapperGetters[key](store.state)
}
Object.defineProperty(store.getters, key, {
get() {
return store._vm[key]
},
})
})
this._vm = new Vue({
data() {
return {
$$state: options.state,
}
},
computed,
})
// ...
}
// ...
}
Copy the code
Back on the page, we can now use getters.info normally. When the name or age changes, the system automatically responds