Vuex is the state manager in VUE. It makes it easy for us to solve the problems of multi-component state synchronization encountered in development. At the same time, the unified management of vUE data through Store can make the data flow clear, traceable and predictable. For some medium to large applications, vuEX can greatly improve the stability and scalability of projects!

The composition of vuex

Vuex is essentially an object that defines four properties, state getters Mutations Actions, to manage the data in the VUE. Store and getters are used to define the state. Use mutation and action to change the state; Module is introduced for modularization segmentation of state; Introducing plug-ins to snapshot, record, and track state; MapState, mapGetters, mapActions, and mapMutations helper functions are provided to facilitate developers to deal with store in the VM.

The core principles of VUEX

  • Vuex exposes a Store class and an install method.
  • Store can inject vUE instance components using the mixin mechanism of vUE and the lifecycle hook beforeCreate of vUE components. During each VUE component instantiation, the vuexInit method is called in front of the beforeCreate hook
  • With new Vue({data: data}), wrap the state in store as a data. Implement responsivity of data in state.

Vuex simple implementation

1. Create a VUE project using vuE-CLI without importing VUex. Create the folder myVuex at the root of the project. The new store.js contains two methods, the State class and the install method.

// store.js
export let Vue;
import applyMixin from './mixin.js';

export class Store {}export const install = () = >{}Copy the code

The install method mixes store globally with the vue.mixin () method. Create mixin.js and modify store.js as follows

// mixin.js
export default function applyMixin (Vue) {
  Vue.mixin({
    beforeCreate: VuexInit
  })
}


function VuexInit () {
  const options = this.$options;
  if (options.store) { // Only the root component instance is bound to the store property
    this.$store = options.store;
  } else if (options.parent && options.parent.$store) { / / child component
    this.$store = options.parent.$store; }}// store.js
export const install = (_vue) = > {
  console.log('-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --'); // Using vue. use calls the install method
  Vue = _vue;
  applyMixin(Vue); // Bind via mixin
}
Copy the code

2. By completing the global injection, we can ensure that we get the this.$store property on every vue component instance. Then we will implement state, getters, mutations and Actions respectively. First of all, how do we define store when we use vuex

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

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    name: 'aaaaa'.age: 1,},getters: {
    myName: state= > state.name + 'sasdsds'.myAge: state= > state.age,
  },
  mutations: {
    add(state, payload) {
      state.age += payload;
    },
    setName(state, payload){ state.name = payload; }},actions: {
    add({ commit }, payload) {
      console.log('commit', commit);
      commit('add', payload); }}})Copy the code

That is, states defined throughout the store are passed as parameters into the Store class. The Store class accepts a single parameter, Options. So let’s implement them separately.

  • state

Define a state property that accepts the state argument in options. Then, by initializing the instance new Vue({data: this.state}), pass the state into the data of the Vue instance to realize the responsiveness of the variables in the state. We also add a state property to the Store class. This property automatically triggers the GET interface, similar to Object.defineProperty({get()}). So we can get the corresponding store from this.$state.store.

// store.js
export class Store {
    constructor(options) {
    console.log(options);
    // --------------------state--------------------------------------
    // Stare defaults to an object that uses new Vue({data: data}) to bind data to
    this.state = options.state || {};
    this._vm = new Vue({
      data: this.state,
    })
  }
  
 get State() { // Attribute accessor new Store().state object.defineProperty ({get()})
    console.log('get state');
    return this._vm.data; }}Copy the code

Importing our own Myvuex in the same way as importing vuex, we can see the result in the component by printing this.$store.state:Thus, we have successfully implemented state in VUEX.

  • getters

We get all the getters methods by walking through them, and when we get getters we get the Get interface through object.defineProperty (). This way we can use getters without parentheses.

// store.js
export class Store {
    constructor(options) {
    // --------------------state--------------------------------------
    // Stare defaults to an object that uses new Vue({data: data}) to bind data to
    this.state = options.state || {};
    this._vm = new Vue({
      data: this.state,
    })
    
     // --------------------=getters--------------------------------------
    let getters = options.getters || {}; There may be multiple methods in getters
    this.getters = {};
    // Walk through the object and get each getter
    Object.keys(getters).forEach((getter) = > {
      Object.defineProperty(this.getters, getter, {
        // Get is automatically called when you want to get the getter
        // Make sure to use the arrow function, otherwise this pointing to the problem
        get: () = > {
          return getters[getter](this.state); }}); }); }get State() { // Attribute accessor new Store().state object.defineProperty ({get()})
    console.log('get state');
    return this._vm.data; }}Copy the code
  • mutations

Mutations, like getters, use mutations objects to store mutations passed in by users. But mutations must submit the status via the commit() method. Therefore, we need to add a comit method to Store.

// store.js
export class Store {
    constructor(options) {
    // --------------------state--------------------------------------
    // Stare defaults to an object that uses new Vue({data: data}) to bind data to
    this.state = options.state || {};
    this._vm = new Vue({
      data: this.state,
    })
    
     // --------------------=getters--------------------------------------
    let getters = options.getters || {}; There may be multiple methods in getters
    this.getters = {};
    // Walk through the object and get each getter
    Object.keys(getters).forEach((getter) = > {
      Object.defineProperty(this.getters, getter, {
        // Get is automatically called when you want to get the getter
        // Make sure to use the arrow function, otherwise this pointing to the problem
        get: () = > {
          return getters[getter](this.state); }}); });// --------------------mutations--------------------------------------
    let mutations = options.mutations || {};
    this.mutations = {}
    Object.keys(mutations).forEach((mutation) = > {
      this.mutations[mutation] = (payload) = > {
        // Pass context and load
        mutations[mutation](this.state, payload); }}); } commit =(type, payload) = > {
    // Pass the method name and parameters to mutations
    // Use the arrow function to prevent this from being unreachable.
    this.mutations[type](payload);
  }
  
  
 get State() { // Attribute accessor new Store().state object.defineProperty ({get()})
    console.log('get state');
    return this._vm.data; }}Copy the code
  • actions

Once mutations is implemented, actions are relatively simple. Again, save the actions passed in and add a dispatch() method to submit the action.

// store.js
export class Store {
    constructor(options) {
    // --------------------state--------------------------------------
    // Stare defaults to an object that uses new Vue({data: data}) to bind data to
    this.state = options.state || {};
    this._vm = new Vue({
      data: this.state,
    })
    
     // --------------------=getters--------------------------------------
    let getters = options.getters || {}; There may be multiple methods in getters
    this.getters = {};
    // Walk through the object and get each getter
    Object.keys(getters).forEach((getter) = > {
      Object.defineProperty(this.getters, getter, {
        // Get is automatically called when you want to get the getter
        // Make sure to use the arrow function, otherwise this pointing to the problem
        get: () = > {
          return getters[getter](this.state); }}); });// --------------------mutations--------------------------------------
    let mutations = options.mutations || {};
    this.mutations = {}
    Object.keys(mutations).forEach((mutation) = > {
      this.mutations[mutation] = (payload) = > {
        // Pass context and load
        mutations[mutation](this.state, payload); }});// --------------------action--------------------------------------
    let actions = options.actions || {};
    console.log(actions, 'actions');
    this.actions = {}
    // We're passing this into actions, so we can get the commit() method and state in actions.
    {commit} is the deconstruction of this when using action
    // add({ commit }, payload) {
    // console.log('commit', commit);
    // commit('add', payload);
    // }
    Object.keys(actions).forEach((action) = > {
      this.actions[action] = (payload) = > {
        actions[action](this, payload);
      }
    })
  }
  
  
  dispatch = (type, payload) = > {
    this.actions[type](payload);
  }

  
  commit = (type, payload) = > {
    // Pass the method name and parameters to mutations
    // Use the arrow function to prevent this from being unreachable.
    this.mutations[type](payload);
  }
  
  
 get State() { // Attribute accessor new Store().state object.defineProperty ({get()})
    console.log('get state');
    return this._vm.data; }}Copy the code

conclusion

This article referred to the network of some big guy’s blog, plus their own understanding. Only the basic state in VUEX is implemented. But through my own manual practice, I also have a new understanding of the use of VUEX.