Vuex

Project creation

In the previous article, we wrote a simple vuE-Router by hand. This time, we will challenge vuex to implement basic functions. As always, let’s create a project and use Vuex

Related components and VUEX configuration

main.js

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

Vue.config.productionTip = false


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

App.vue


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

<script>


export default {
  name: 'HelloWorld',}</script>

<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

Copy the code

Then the vuex configuration store/index.js

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    counter: 0
  },
  mutations: {
    add(state) {
      state.counter++
    }
  },
  actions: {
    add({commit}) {
      setTimeout(() = > {
        commit('add')},1000); }}})Copy the code

Project start

This successfully implements the use of VUex in components

Now our goal is to code our own VUEX

Handwritten Vuex

Documents to prepare

Create myStore file

main.js

import Vue from 'vue'
import App from './App.vue'
// import store from './store'
import store from './mystore' //store points to change

Vue.config.productionTip = false


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

mystore/index.js

import Vue from "vue";
import Vuex from "./myvuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    counter: 0,},mutations: {
    add(state){ state.counter++; }},actions: {
    add({ commit }) {
      setTimeout(() = > {
        commit("add");
      }, 1000); }}});Copy the code

Demand analysis

As with vuE-Router, the following requirements need to be implemented in order to implement Vuex:

  • To use vuex as a plug-in, you need to implement the Store class and install method
  • Implementation of the Sotre class:
    • You need responsive data state
    • The Store instance needs to be mounted to the Vue instance
    • Commit and Dispatch methods implemented

Vuex basic structure

Recall the steps you took when using vuex

  • First introducedimport Vuex from 'vuex'
  • To installVue.use(Vuex);
  • Final instantiationnew Vuex.Store({... })

Unlike vue-Router, vuex is not instantiated, but vue.store. What does this mean, that Vuex itself contains the store constructor and install method, that Vuex should have the following basic structure

mystore/myvuex.js

let Vue

class Store{
   constructor(){}}function install(_Vue) {}export default {Store,install}


Copy the code

Mount the $Store instance on the VUE component

As with VUE, adding store instances to vUE components can be done by blending in. (Because vue. use(Vuex) is executed first, the install method cannot get the store instance directly.) ,

/ /... class Store

function install(_Vue) {
    Vue=_Vue
    console.log(Vue)
     Vue.mixin({
       beforeCreate() {
         // At this point, the context is already the component instance
         // If this is the root instance, its $options will have a store instance
         if (this.$options.store) {
           Vue.prototype.$store = this.$options.store;
           // Then you can get $store in the component}}}); }Copy the code

Reactive data state

You need to define reactive data state in the Store class, so that $store.state can be used in the component, and the page can be updated when state changes

let Vue
class Store{
   constructor(options){
   // Save options
    this.$options=options;
    const state=this.$options.state || {};
    // Define reactive data $$state
    Vue.util.defineReactive(this."$$state", state);
   }
   // Expose state
   get state() {return this.$$state
   }
   set state(v) {console.error('please use replaceState to reset state'); }}Copy the code

Implement commit and Dispatch methods

Post all the code here

let Vue

class Store{
   constructor(options){

    // Save mutations and actions
    this._mutations = options.mutations
    this._actions = options.actions
    this.$options=options;
    const state=this.$options.state || {};
    Vue.util.defineReactive(this."$$state", state);
    // We can bind this to the current store instance to avoid problems with the direction of this
    this.commit = this.commit.bind(this)
    this.dispatch=this.dispatch.bind(this)}commit(type,payload){
     // Find the user-defined mutation method based on type
     const entry = this._mutations[type];
     if(entry){
         entry(this.state,payload)
     }
   }

   dispatch(type,payload){
       const entry = this._actions[type];
       console.log(`entry`, entry);
       if (entry) {
         entry(this, payload); }}get state() {return this.$$state
     
   }

   set state(v) {console.error('please use replaceState to reset state'); }}function install(_Vue) {
    Vue=_Vue
     Vue.mixin({
       beforeCreate() {
         // At this point, the context is already the component instance
         // If this is the root instance, its $options will have a store instance
         if (this.$options.store) {
           Vue.prototype.$store = this.$options.store; }}}); }export default { Store, install };

Copy the code

Finished, the basic function of Vuex has been realized, isn’t it very simple, we can try it together