Introduction: VuEX is a part of the whole Vue bucket to control the data flow, and it is also a technical point frequently asked in the interview questions. We often use it in the development of VUEX. What is the principle behind the strong dependence of VUEX on data control, modification and Vue

  1. The first part goes back to the whole vuex concept, installation, as well as borrowing a simple example from the official, ash often familiar friends, can directly skip over… OUO!
    • What is Vuex?

      Vuex is a state management mode developed specifically for vue.js applications. It uses centralized storage to manage the state of all components of an application and rules to ensure that the state changes in a predictable way. Vuex is also integrated into Vue’s official debugging tool devTools Extension (Opens New Window), providing advanced debugging functions such as zero-configuration time-travel debugging and state snapshot import and export.

    • What is “state management mode”?

      The state self-management application consists of the following parts:

      • State, the data source that drives the application;

      • View, to declaratively map state to the view;

      • Actions, in response to changes in state caused by user input on the view.

        Here is a simple illustration of the idea of “one-way data flow” :

        However, the simplicity of one-way data flow can easily be broken when our application encounters multiple component shared state:

        • Multiple views depend on the same state.

        • Actions from different views need to change the same state.

        For problem one, the method of passing parameters can be cumbersome for multi-layer nested components and does nothing to transfer state between sibling components. For problem two, we often use parent-child components to reference directly or to change and synchronize multiple copies of state through events. These patterns are very fragile and often result in unmaintainable code.

        So why don’t we extract the shared state of the components and manage it in a global singleton? In this mode, our tree of components forms a giant “view” where any component can get state or trigger behavior no matter where it is in the tree!

        By defining and isolating concepts in state management and by enforcing rules to maintain independence between views and states, our code becomes more structured and maintainable.

        This is The basic idea behind Vuex, which borrows from Flux (a Labour of New Window), Redux (a Labour of New Window) and The Elm Architecture (a Labour of New Window). Unlike other patterns, Vuex is a state management library designed specifically for vue.js to leverage the fine-grained data response mechanism of vue.js for efficient state updates.

        However, the simplicity of one-way data flow can easily be broken when our application encounters multiple component shared state:

        • Multiple views depend on the same state.

        • Actions from different views need to change the same state.

        For problem one, the method of passing parameters can be cumbersome for multi-layer nested components and does nothing to transfer state between sibling components. For problem two, we often use parent-child components to reference directly or to change and synchronize multiple copies of state through events. These patterns are very fragile and often result in unmaintainable code.

        So why don’t we extract the shared state of the components and manage it in a global singleton? In this mode, our tree of components forms a giant “view” where any component can get state or trigger behavior no matter where it is in the tree!

        By defining and isolating concepts in state management and by enforcing rules to maintain independence between views and states, our code becomes more structured and maintainable.

        This is The basic idea behind Vuex, which borrows from Flux (a Labour of New Window), Redux (a Labour of New Window) and The Elm Architecture (a Labour of New Window). Unlike other patterns, Vuex is a state management library designed specifically for vue.js to leverage the fine-grained data response mechanism of vue.js for efficient status updates.)

    • The installation

      NPM

      npm install vuex --save
      Copy the code

      Yarn

      yarn add vuex
      Copy the code

      Vue-cli scaffolding comes with it

      vue add vuex
      Copy the code

      In a modular packaging system, Vuex must be explicitly installed via vue.use () :

      import Vue from 'vue'import Vuex from 'vuex'​Vue.use(Vuex)
      Copy the code
    • If you’re not familiar with vuex, check out the official documentation and Github address

  2. After installation, using the official case, using the simplest addition case, the whole vuex uses 4 files: store/index.js,store/my-vuex.js,main.js and the application component (home.vue).
    • File directory structure

    • store/index.js

      Import Vue from 'Vue' // import Vuex from 'Vuex' annotates the official import Vuex from './my-vuex' // Install vue. use(Vuex) export default new vuex. Store({state: {count: 0,}, mutations: { setCount(state, payload) { state.count += payload }, }, actions: { asyncSetCount({ commit }, payload) { setTimeout(() => { commit('setCount', payload) }, 1000) }, }, gutters: { guttersCount(state) { return state.count * 2 }, }, })Copy the code
    • Main.js, the package entry for vue projects

      import Vue from 'vue' import App from './App.vue' import router from './router' import store from './store' Vue. Config. productionTip = false new Vue({router, // this is our new Store instance!! $mount('# App ') render: h => h(App)}).$mount('# App 'Copy the code
    •   <template>
          <div class="home">
            <h3>{{ $store.state.count }}</h3>
            <h3>gutters:{{ $store.gutters.guttersCount }}</h3>
            <button @click="$store.commit('setCount', 1)">mutation</button>
            <button @click="$store.dispatch('asyncSetCount', 2)">async</button>
          </div>
        </template>
        
        <script>
        export default {
          name: "Home"
        };
        </script>
      Copy the code
    • Then comes our main character, My-Vuex. Let’s analyze the principle of VUEX step by step and manually implement a simple VUex

  3. Implement VUEX manually

    • First of all, Vuex is a plug-in system of Vue, so the implementation will have the most basic two parts, respectively Store instance and install plug-in method. We first set up a basic Vue plug-in shelf, among which, we usually use vuue. Use (‘ plug-in ‘) method to realize the inST of the plug-in All method and pass in an instance of Vue to associate the Vue instance with the plug-in

      Let Vue class Store {constructor(options){this.options = options}} Function install(_Vue){Vue = _Vue} function install(_Vue){Vue = _Vue} Export default {store, install} export default {store, install}Copy the code
    • In this case, our page must report an error, the page does not have the store attribute, so where do we get it? In main.js we actually have the Store instance that we imported from the beginning. In the root instance, we can use the Store property, so where do we get it? In main.js we actually have the Store instance that we imported from the beginning. In the root instance, we can use the Store property, so where do we get it? In main.js, there is the Store instance that we imported at the beginning. In the root instance, we can get it by means of options, and we can mix it into the global instance by using Vue mixin, where our mixing time is put on the global beforeCreate

      Function install(_Vue){Vue = _Vue // Mount only at the first global initialization to avoid repeated mount of sub-components Prototype.$stroe = this.$options.store}}Copy the code
    • After the previous step, store is mounted in the Vue prototype, it is necessary to implement the properties and methods in VUEX concretely. The basic requirements are first set up.

      Mutations = options. Mutations this.actions = options.actions} dispatch(){} commit(){} }Copy the code
    • Update (Vue) {update (Vue, Vue, Vue, Vue, Vue, Vue, Vue, Vue, Vue, Vue, Vue, Vue, Vue, Vue State is processed in a responsive manner. The first is vue.util.definereactive (). In the previous vue-router article, we implemented a new Vue instance and defined the data on date In, the request for state can be proxied to our new Vue instance by using accessor method, and state is allowed to be modified directly. We should implement the code by mutation

      Mutations = options. Mutations this.actions = Options. actions this._vm = new Vue({data:{// add $$character to prevent Vue from proxy State $$state:options.state}})} get state(){//$data = $data Return this._vm.$data.$$state} set state(){console. ') } dispatch(){} commit(){} }Copy the code
    • Now for the realization of the method, in fact, when we use dispatch and commit methods, we will pass in two parameters, including actions and mutations. In fact, it is very simple to realize. It should be noted that in action, asynchronous requests and other situations are often handled, and its “This” points to chaos, so In this case, the dispatch,commit method this points to the binding

      Mutations = options. Mutations this.actions = options.actions This._vm = new Vue({data:{$$state = new Vue); options.state } }) this.dispatch = this.dispatch.bind(this) this.commit = this.commit.bind(this) } get state(){ //$data Return this._vm.$data.$$state} set state(){console. ')} // You need to pass in the parameters dispatch(type,payload){// The parameters in the actions method are also passed in here // We usually write {commit} in the first parameter, with dispatch,state, etc., for more complex business logic // Actions [type](this,payload)} // Actions [type](this,payload)} Mutations are the mutations method, and you need to pass in the parameters commit(type,payload){//mutation is simple, passing in state, and payload changes the state this.mutation[type](this.state,payload) } }Copy the code
    • This leaves the gutter argument, which translates to the output of the gutters object’s method after passing state, which can also be implemented using an accessor scheme

      Keys (this.options.gutters).foreach ((key) => (obj[key] =  this.options.gutters[key](this.state)) ) return obj }Copy the code

      However, this method is rather superficial. Although it works, it is inefficient to run this through gutters every time. In fact, when we write gutters, we often use it in computed in Vue, so we can also take advantage of this, remember this._vm Mputed runs this route through gutters

      let Vue class Store { constructor(options) { this.mutations = options.mutations this.actions = options.actions _wrapGutters = options. Gutters = {} // This after the gutterr proxy to this._vm calculated property const Computed = {} // Prevent this pointing from losing const store = this object.keys (this._wrapgutters). ForEach (key=>{const fn = this._wrapGutters[key] computed[key] = function (){ return fn(store.state) } // Our gutter property is read-only, and in a computed property pointing to this_VM when called, object.defineProperty can be used to implement Object.defineProperty(this.gutters,key,{ Get (){return () => store._vm[key]}})}) this._vm = new Vue({// Take gutters to here computed, data: {$$state: options.state, }, }) this.commit = this.commit.bind(this) this.dispatch = this.dispatch.bind(this) } get state() { return This._vm.$data.$$state} set state(v) {console.log(' no change ')} // get gutters() {// const obj = {} // Object.keys(this.options.gutters).forEach( // (key) => (obj[key] = this.options.gutters[key](this.state)) // ) // return  obj // } commit(type, payload) { this.mutations[type](this.state, payload) } dispatch(type, payload) { this.actions[type](this, payload) } }Copy the code

      So this is Gutters, this is a simple vuex handwritten part, hope you get something

  4. Conclusion:
    • Vue plug-in mechanism, need to implement install method,install the first parameter for Vue instance, need to save globally

    • It saves the attributes in Gutters as its own instance attributes in vuex, gets the Store instance in main.js, mixes the Stroe instance globally through vuue. Mixin method, and mixes it into the prototype of Vue root instance at the first initialization for invocation in various components

    • Change the state value in store into responsive data using the method of “borrow a goose to lay an egg”, so that when the state changes, the corresponding update function is triggered

    • When dealing with Gutters, the computed property of the global Vue was used to make the gutter more efficient and caching efficient

Previous article Vue in-depth learning series: VuE-Router core principles of learning anatomy

If there is any infringement in the article, please contact me