A thorough understanding of the state management of Vuex3

1. What is Vuex

Anyone who has known Vuex knows that it is Vue's official state management solution; it can communicate between father and son, grandparents and sibling components;

In addition to using Vuex, we all know that there is another solution that can satisfy the communication between any components, that is, the vue global event bus ($ bus) ;

In the data receiving component, $on is used to bind an event (eventName), and the second parameter binds a callback function to receive data.

//接收数据的组件
this.$bus.$on('eventName',(value)=>{
    
    
   console.log(value) //{a:1,b:2}
})

In the data sending component, use $emit to submit to the bound event (eventName), and the following parameters are the data to be passed;

//发送数据的组件
var obj = {
    
    a:1,b:2}
this.$emit('eventName',obj)

So since the Vue global event bus ($ bus) can satisfy the communication between any components, why does the Vue official create Vuex again?

Vue global event bus

Let's take a look at the following scene (using event bus for data sharing) The picture comes from Shang Silicon Valley

insert image description here
As can be seen from the figure above, there is an X attribute in the data in the A component, and B, C, and D components also need it. The shared attribute can use $on to get the X attribute; it looks like this, doesn’t it feel very simple, nothing Ah, don't worry, this is just reading attributes, so what if B, C, and D need to be modified?

In fact, you only need to use the $emit event in the B, C, and D components to send the modified value to the A component, and the A component accepts it through $on and then modifies the X attribute. Does it feel confusing to just look at the text? , which is shown in the picture below: The picture comes from Shang Silicon Valley

insert image description here
The red arrows indicate that B, C, and D components read the shared attribute X, and the green arrows indicate that B, C, and D components modify the X attribute;

The current scene only shows that all four components need a shared attribute X. After reading and writing, it looks very messy. If there are more than a dozen or dozens of components in a large project, a shared attribute X is required, isn’t it? more messy;

Vuex state management

So what if you want to use Vuex to share the X attribute? Look at the picture below: The picture comes from Shang Silicon Valley

insert image description here
Vuex is an existence independent of any component. Put the properties that A, B, C, and D components need to share into Vuex for management, and the properties that do not need to be shared are still written in the original component; at this time, A, B, C, D Components and Vuex are two-way arrows, that is, components can be read or modified through their built-in apis. When a component modifies shared properties, other components get the latest modified data;

When to use Vuex

The Vue event bus is actually very convenient, but it is suitable for small projects; for large projects, Vuex is the best choice for centralized management of shared state, which is convenient for use and maintenance;

Here comes the question, I don't know what to do with the size of the project, when is it suitable to use Vuex?

  • Multiple components in the project need to use or modify a common state (multiple components share the same state)

2. Pure vue component case

I originally planned to directly introduce the code steps and methods of introducing Vuex, but in order to better understand and compare, I will first show you the demo and code of the two component cases I wrote, and I will show you the code after introducing Vuex later , although the functions are exactly the same, the main reason is that the internal code of the component before and after Vuex is used is different;

Calculate Total Cases

The calculation total case component of navigation 2:
insert image description here
the code is as follows:

<template>
    <div>
        <h3 style="marginBotton:10px;">此时导航三组件内总人数为:???</h3>
        <h3 :style="{marginBottom:'10px'}">当前计算的和为:{
    
    {
    
    count}}</h3> 
        <el-select v-model.number="value" size="mini"  :style="{width:'60px'}" placeholder="0">
            <el-option
            v-for="item in options"
            :key="item.value"
            :label="item.label"
            :value="item.value">
            </el-option>
        </el-select>
        <el-button size="mini" @click="jia">+</el-button>
        <el-button size="mini" @click="jian">-</el-button>
        <el-button size="mini" @click="oddJia">和为奇数 +</el-button>
        <el-button size="mini" @click="asyncJia">1秒后 +</el-button>
    </div>
</template>
<script>
export default {
    
    
    data(){
    
    
        return{
    
    
            count:0,
            options: [
                {
    
    value: 1,label: '1'},
                ...
            ],
            value: null
            }
    },
    methods:{
    
    
         jia(){
    
    
           this.count += this.value
         },
         jian(){
    
    
           this.count -= this.value
           if(this.count <= 0){
    
    
               this.count = 0
           }
         },
         oddJia(){
    
    
             if(this.count%2 !== 0){
    
    
                this.jia()
             }
         },
         asyncJia(){
    
    
             setTimeout(() => {
    
    
                 this.jia()
             },1000)
         }
    }
}
</script>

Add people case

Navigator 3 Add personnel case component:
insert image description here
the code is as follows:

<template>
    <div>
         <el-select v-model="value" placeholder="请选择添加人员">
            <el-option
            v-for="item in options"
            :key="item.name"
            :label="item.name"
            :value="item.name">
            </el-option>
        </el-select>
        <el-button  @click="addPerson">添加</el-button>
        <el-button  @click="rest">还原</el-button>
        <el-table
            :data="filterTable"
            :border='true'
            style="width: 100%;marginTop:10px">
            <el-table-column
                align="center"
                prop="name"
                label="姓名">
            </el-table-column>
            ...
        </el-table>
        <h3 style="marginTop:10px;">此时表格总人数为:{
    
    {
    
    filterTable.length}}</h3>
        <h3 style="marginTop:10px;">此时导航二组件的计算总和为:???</h3>
    </div>
</template>
<script>
export default {
    
    
    data() {
    
    
        return {
    
    
           value:'',
           options: [
                {
    
    name: '王朝', sex:'男',age:21,hobby:'武术'}, 
                ...
            ],
            tableData: [
                {
    
    name: '张三', sex:'男',age:18,hobby:'唱歌'}, 
                {
    
    name: '李四', sex:'女',age:20,hobby:'跳舞'},   
            ],
           filterTable:[]
        }
    },
    mounted(){
    
    
        this.filterTable.push(...this.tableData)
    },
    methods:{
    
    
        addPerson(){
    
    
            var isHave = true
            this.filterTable.forEach( e => {
    
    
                if(e.name == this.value)  isHave = false
            })
            if(!isHave){
    
    
                this.$message({
    
    
                    message: '人员已添加!',
                    type: 'warning',
                    duration:1000
                })
                return
            }

           var person =  this.options.filter( item => {
    
    
                return item.name == this.value
            })
            this.filterTable.push(person[0])
        },
        rest(){
    
    
           this.filterTable = this.tableData
        }
    }
}
</script>

At this time, the two components are completely independent, and no data sharing is realized, so the place where the data in the other component is used is marked with "???";

Next, we started to use Vuex step by step to realize data sharing between two components;

3. Vuex working principle and process

The following is the working principle diagram of Vuex given by the official, as follows:
insert image description here
If you want to use Vuex very familiarly, then we should first understand its working principle and its internal operating mechanism, then we can say goodbye to rote memorization, and we can easily Familiar with writing code fluently;

From the working principle diagram above, we can see that there are three most important core objects in Vuex, Actions, Mutations, and State. What is the relationship between them, and how can they assist in the operation? Let's take a look at the workflow of Vuex;

The first workflow

For the convenience of understanding, I made some annotations on the working principle diagram of Vuex, as shown in the figure below:
insert image description here
The red arrow is the workflow of the component using Vuex. With the above figure, carefully understand the following text and see how the component modifies the shared data:

  1. The dispacth() function is called in the vue component, and there are two parameters in the function, the first parameter is a method name 'key1', and the second parameter is the value passed in
  2. Since the component calls dispatch, it will find a parameter 'key1' passed in by the dispatch function in the Actions object;
  3. After key1 is found, the corresponding function is called; the key1 function calls the commit() function inside. The commit() function also has two parameters, the first parameter is a method name 'KEY1', and the second parameter is the incoming value;
  4. Since commit is called, the first parameter 'KEY1' passed in by the commit function will be found in the Mutations object;
  5. After the Mutations object finds the function corresponding to 'KEY1', Vuex internally calls Mutate to modify the state, and renders the component that modifies the state after modifying the state

The second workflow

Now you should understand the general flow of its work. Don’t worry, it’s not over yet. Let’s continue to look at the picture below:
insert image description here
This should be the most complete workflow flow chart. In addition to the outermost workflow we introduced just now, the components are also You can directly call commit() to modify the state; then how to distinguish and use it?

  • Vuex has internal regulations. Actions mainly write some complex business logic and asynchronous processing, and Mutations mainly modify the state;
  • If you can get the value that needs to be passed in the component, there is no need to perform too much business logic processing on the value internally, you can directly commit() to call the modification state function in Mutations
  • If the value that needs to be passed needs to be obtained through the interface, and then complex business logic needs to be performed, it is best to put it in the Actions function for processing;
  • The advantage of this is that the Devtools development tool can accurately monitor changes in the Vuex state;

Working principle of life-like Vuex

The above is the entire working principle and process of Vuex; but in order to let everyone remember and understand better, I simulated the following scene:
insert image description here

Vuex is equivalent to a restaurant, the vue component is the customer, the actions are the waiter, the mutations are the chef, and the state is the cooked dishes and meals; we change the task of modifying the shared state into ordering, and we can go through the ordering process:

The process of ordering food through the waiter:

  • First of all, customers need to ask when ordering because they are not familiar with restaurant dishes, so they have to find 'waiter 1' to order, or order by scanning the takeaway platform on the table
  • Secondly, after 'waiter 1' arranges the menu, it is handed over to the back kitchen 'chef 1' to do it. The back kitchen is equipped with monitoring, and if you want to know which chef cooks which customer's dish, you can query it;
  • Finally, chef 1 prepares the dishes, and the customers can get them directly;

The process of ordering by customers themselves:

  • First of all, the customer is very familiar with the restaurant, the cuisine, and the chef, so it is very simple, just go to 'Chef 1' and order a few dishes;
  • Finally, chef 1 prepares the dishes, and the customers can get them directly;

Now you should be very familiar with the workflow of Vuex, it is very simple, just learn to order, haha, then we will start using Vuex;

4. Introduce Vuex into the project

Install Vuex

First, you need to install the node environment on your computer, using npm to install:

npm install vuex --save

create store

Then create a store folder under the project src folder, and create index.js in it:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
    
    
  state: {
    
    },
  getters:{
    
    },
  mutations: {
    
    },
  actions:{
    
    },
  modules:{
    
    }
})
export default store

Mount store in Vue

Finally, import the created store in the main.js file:

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

new Vue({
    
    
  el: '#app',
  components: {
    
     App },
  template: '<App/>',
  store
})

Five. Vuex's core attribute usage

If you know how to use one component, the other is not a problem. Here I take the calculation of the total component as an example;

When creating a store instance, you can see that there are five core attributes inside Vuex. Next, we will start with these five core attributes and realize all the original functions of the total calculation case step by step;

Delete all the logic codes of the calculation total component, and the demo is as shown in the figure below:

insert image description here
code show as below:

<template>
    <div>
        <h3 style="marginBotton:10px;">此时导航三组件内总人数为:???</h3>
        <h3 :style="{marginBottom:'10px'}">当前计算的和为:???</h3> 
        <el-select v-model.number="value" size="mini"  :style="{width:'60px'}" placeholder="0">
            <el-option
            v-for="item in options"
            :key="item.value"
            :label="item.label"
            :value="item.value">
            </el-option>
        </el-select>
        <el-button size="mini" @click="jia">+</el-button>
        <el-button size="mini" @click="jian">-</el-button>
        <el-button size="mini" @click="oddJia">和为奇数 +</el-button>
        <el-button size="mini" @click="asyncJia">1秒后 +</el-button>
    </div>
</template>
<script>
export default {
    
    
    data(){
    
    
        return{
    
      
            options: [
                {
    
    value: 1,label: '1'},
                ...
            ],
            value: null
            }
    },
    methods:{
    
    
         jia(){
    
    },
         jian(){
    
    },
         oddJia(){
    
    },
         asyncJia(){
    
     }
    }
}
</script>

single source of truth (state)

The first is the state configuration, whose value is an object used to store the shared state; Vuex uses the single tree principle to put all the states on this object for easy positioning and maintenance;

We put the count of the total count component into the state in Vuex, as follows:

...
const store =  new Vuex.Store({
    
    
  state: {
    
    
    count:0
  }, 
})
...

Get it in the component, you can do this:

...
 computed:{
    
    
       count(){
    
    
           return this.$store.state.count
       }
  },
...

If there are many shared state attributes that need to be introduced in the component, it will be more troublesome to use this.$store.state.x, so Vuex provides us with the mapState() auxiliary function to obtain them, as follows:

import {
    
    mapState} from 'vuex'
 ...
 computed:{
    
    
  //参数为对象写法
   ...mapState({
    
    
     //key值随意自定义,模板中插值也要写入自定义的key值
       count:'count' 
   })
   //参数为数组写法
   // 此时组件定义的属性名要和state中定义的属性名一致
  ...mapState(['count'])
  },
  ...

In the above two acquisition methods, the component can obtain the shared count attribute and display it on the page, as shown in the following figure:

insert image description here

State update method (mutations)

The state in Vuex is different from the state in the component, and cannot be modified directly in the way of state.count = 'xx'; the only way for Vuex to modify the state is to submit a mutation;

Mutation is a function, the first parameter is state, and its function is to change the state of the state;

Next, let's define a mutation to update the state of count in the function:

const store =  new Vuex.Store({
    
    
  state: {
    
    
    count:0
  },
  mutations: {
    
    
    //更改count方法,type为增加
    JIA(state,count){
    
    
      state.count += count
    }
  }
})

Submit the commit function in the component to trigger the JIA function defined in mutattions:

...
 methods:{
    
    
    jia(){
    
    
         this.$store.commit('JIA',this.value)
     }
 }
 ...

Or use the most commonly used mapMutations auxiliary function, as follows:

...
 //把获取的单选框的value值,通过参数传给mutation定义的jia函数,
 <el-button size="mini" @click="JIA(value)">+</el-button>
 ...
 import {
    
    mapMutations} from 'vuex'
 ...
  methods:{
    
    
     //对象参数中的key值为自定义的点击事件名
      ...mapMutations({
    
    JIA:'JIA'}),
      //参数为数组,此时点击事件名要和mutation中定义的增加事件名一致
       ...mapMutations(['JIA',]),
  }

The above two methods can achieve adding functions, as shown in the figure below:

insert image description here

Computed properties (getters) in the store

Sometimes we need to derive some states from the state in the store, such as filtering and counting the list, here we simply increase the total number of calculations by 10 times:

The Getter accepts state as its first parameter, as follows:

const store =  new Vuex.Store({
    
    
  state: {
    
    
    count:0
  },
  getters:{
    
    
    multipleCount(state){
    
    
      return state.count * 10
    }
  }
})

Components can be obtained in this way, as follows:

<h3>当前计算的和的10倍为:{
    
    {
    
    multipleCount }}</h3> 
...
 computed:{
    
    
    multipleCount(){
    
    
        return  this.$store.getters.multipleCount
    },
 },

Or use the auxiliary function mapGetters to get it, the same as the introduction of mapState, as follows:

import {
    
    mapGetters} from 'vuex'
...
computed:{
    
    
    //对象写法
    ...mapGetters({
    
    
        multipleCount: 'multipleCount'
    }),
    
    //数组写法
    //此时自定义的函数名要和getter中定义的函数名一致
   ...mapGetters(['multipleCount']),
 },

The getter function can be obtained in the above two ways, as shown in the following figure:

insert image description here

Update state asynchronously (actions)

Action is similar to mutation, the difference is:

  • Actions submit mutations instead of directly changing the state.
  • Action can contain arbitrary asynchronous operations.

The biggest difference is that some business logic and asynchronous operations can be written in action; while mutation is a simple change of state;

How to put it, in fact, action is like an intermediary connecting components and mutations. Both synchronous and asynchronous operations can be completed in action. It just helps us commit the functions in mutations in the actions function;

Sync increase total

Next, let's use action again to realize clicking the JIA function to increase the total number (synchronous operation), as follows:

const store =  new Vuex.Store({
    
    
  state: {
    
    
    count:0
  },
  mutations: {
    
    
    JIA(state,count){
    
    
      state.count += count
    }
  },
  actions:{
    
    
   //第一个参数为context(上下文),第二个参数为传的值
    jia(context,value){
    
    
     console.log(context) //打印结果如下图
      context.commit('JIA',value)
    }
  },
})

This is the result of console.log(context), which is an object that contains commit, dispatch, getters and other methods, like a small srore, but different from store, we call it context here; since context is an object,
insert image description here
if If we only need to commit, we can also use the method of data deconstruction to write, as shown in the following figure:

 actions:{
    
    
   //第一个参数为context(上下文),第二个参数为传的值
    jia({
     
     commit},value){
    
    
        commit('JIA',value)
    }
  },

Components can dispatch actions, which are triggered by the store.dispatch method:

methods:{
    
       
    jia(){
    
    
          this.$store.dispatch('jia', this.value)
      },
}

Or trigger through the mapActions helper function:

import {
    
     mapActions} from 'vuex'
...
methods:{
    
       
   //对象参数中的key值为自定义的点击事件名
   ...mapActions({
    
    jia:'jia'}), 
   //数组参数
   //此时点击事件名要和action中定义的增加事件名一致
   ...mapActions(['jia']), 
}

We can use both actions and mutations to implement the function of JIA functions to increase the total number; the question is, we can call the JIA functions defined in mutations, why bother to call mutations in actions, and then distribute actions?

Of course, here we just demonstrate it for your reference. In general, we will not put it into actions for synchronous operations. We can directly update the status in the project and submit the mutation function directly in the component commit;

Increment total asynchronously

Since the project does not write the background service, it is mock data, here we use the timer to write it asynchronously, as shown in the figure below:

 actions:{
    
    
    asyncJia({
     
     commit},value){
    
    
        setTimeout(() => {
    
    
          context.commit('JIA',value)
        },1000) 
    }
 },

The method of distributing action in the component is as follows:

 methods:{
    
    
       asyncJia(){
    
    
           this.$store.dispatch('asyncJia',this.value)
        }
  }

Similarly, you can also use the mapActions function, as follows:

import {
    
     mapActions} from 'vuex'
...
methods:{
    
       
   // //对象参数中的key值为自定义的点击事件名
   ...mapActions({
    
    asyncJia:'asyncJia'}), 
    //数组参数,此时点击事件名要和action中定义的增加事件名一致
   ...mapActions(['asyncJia']), 
}

Regardless of synchronous and asynchronous operations, the above methods can achieve the function of increasing the total number;

Why do asynchronous processing in actions

Then the question comes, why can asynchronous operations be processed in actions, but not in mutations?

The above is some simple business logic. The timer or odd number judgment in the action can actually be completed in the mutation, so it feels like the action is redundant;

The official stated clearly:

  • The significance of synchronization in mutations is that after each mutation is executed, the corresponding state can be obtained, which is convenient for Vuex's devtools tool to track state changes
  • If you write asynchronously in mutations, the devtools tool will not know when the status is updated, so there are actions
  • Actions are used to deal with asynchronously. When mutations are triggered inside, you can clearly see when the mutation was recorded, and you can check the corresponding status immediately, so that asynchronous updates can also see the process of updating the status;

For example, when encountering some complex business logic, the second asynchronous operation may depend on the result of the first operation;

code show as below:

actions:{
    
    
    asyncJia({
     
     commit},value){
    
    
      return new Promise((resolve,reject) => {
    
    
        setTimeout(() => {
    
    
          context.commit('JIA',value)
          resolve()
        },1000)
      })  
    }
 },

After calling this asynchronous increase function in the component, wait 1 second after returning the result to call the increase function, the code is as follows:

...
<el-button size="mini" @click="doubleAsync(value)">异步 + 后再等1秒后 +</el-button>
...
import {
    
    mapMutations, mapActions} from 'vuex'
...
methods:{
    
    
     ...mapMutations(['JIA','JIAN']),
      ...mapActions(['oddJia','asyncJia']),
      doubleAsync(){
    
    
          this.asyncJia(this.value).then(() => {
    
    
            setTimeout(() => {
    
    
               this.JIA(this.value)
            },1000)
          })
      }
  }

The demo case is as follows:

insert image description here
The division of labor is clear, so it looks clear and easy to operate;

Extension : In fact, asynchronous operations can also be implemented in matations, or you don’t need mutations, you can directly change the state in the action, and the page functions can also be used and displayed normally; but as mentioned above, if Vuex has no operating rules, everyone can do whatever they want To write logic code, the devtools tool will not track it correctly, which is not convenient for later maintenance, and the code is also very messy, so we still follow the standard recommended by Vuex to use it;

There is also a modules module that has not been introduced, so don’t worry. At present, we have only realized the association between a single component and Vuex, and only introduced the api usage of core attributes, and have not realized multi-component data sharing;

The detailed Vuex version codes of the two components in the project are shared below for reference.

6. Complete code using Vuex components

store warehouse code

import Vue from 'vue'
import Vuex from 'vuex'
import {
    
    message} from 'element-ui'
Vue.use(Vuex)

const store =  new Vuex.Store({
    
    
  state: {
    
    
    count:0,
    filterTable:[]
  },

  getters:{
    
    
    multipleCount(state){
    
    
      return state.count * 10
    }
  },

  mutations: {
    
    
    JIA(state,count){
    
    
      state.count += count
    },
    JIAN(state,count){
    
    
      state.count -= count
      if(state.count <= 0) state.count = 0
    },
    ADDPERSON(state,person){
    
    
      state.filterTable.push(...person)
    },
     //这个重置方法本不需要,只是为了组件使用commit
     //dispatch('restPerson')就可以实现,这里为了下面讲解知识点而用
    RESTPERSON(state,person){
    
    
        state.filterTable = []
        state.filterTable.push(...person)
     }
  },

  actions:{
    
    
    asyncJia(context,value){
    
    
      return new Promise((resolve,reject) => {
    
    
        setTimeout(() => {
    
    
          context.commit('JIA',value)
          resolve()
        },1000)
      })  
    },
    oddJia({
     
     commit,state},value){
    
    
       if(state.count%2 !== 0){
    
    
        commit('JIA',value)
       }
    },
    addPerson({
     
     commit,state},obj){
    
    
      var isHave = true
      state.filterTable.forEach( e => {
    
    
          if(e.name == obj.value)  isHave = false
      })
      if(!isHave){
    
    
          message({
    
    
              message: '人员已添加!',
              type: 'warning',
              duration:1000
          })
          return
      }
      
      var person =  obj.options.filter( item => {
    
    
        return item.name == obj.value
      })
      commit('ADDPERSON',person)
    },
    restPerson({
     
     commit,state},value){
    
    
       state.filterTable = []
       commit('ADDPERSON',value)
    }
  },
})

export default store

Calculate Total Cases

The code of the navigation 2 calculation total case component is as follows:

<template>
    <div>
        <h3 style="marginBotton:10px;">此时导航三组件内总人数为:???</h3>
        <h3>当前计算的和为:{
    
    {
    
    count}}</h3> 
        <h3 :style="{marginBottom:'10px'}">当前计算的和的10倍为:{
    
    {
    
    multipleCount }}</h3> 
        <el-select v-model.number="value" size="mini"  :style="{width:'60px'}" placeholder="0">
           ...
        </el-select>
        <el-button size="mini" @click="JIA(value)">+</el-button>
        <el-button size="mini" @click="JIAN(value)">-</el-button>
        <el-button size="mini" @click="oddJia(value)">和为奇数 +</el-button>
        <el-button size="mini" @click="asyncJia(value)">1秒后 +</el-button>
        <el-button size="mini" @click="doubleAsync(value)">异步 + 后再等1秒后 +</el-button>
    </div>
</template>
<script>
import {
    
    mapState,mapGetters,mapMutations, mapActions} from 'vuex'
export default {
    
    
    data(){
    
    
        return{
    
      
            options: [
                {
    
    value: 1,label: '1'},
                ...
            ],
            value: null
            }
    },
    computed:{
    
    
        ...mapGetters(['multipleCount']),
        ...mapState(['count'])
    },
    methods:{
    
    
        ...mapMutations(['JIA','JIAN']),
        ...mapActions(['oddJia','asyncJia']),
        doubleAsync(){
    
    
            this.asyncJia(this.value).then(() => {
    
    
              setTimeout(() => {
    
    
                 this.JIA(this.value)
              },1000)
            })
        }
    }
}
</script>

Add people case

Navigate 3 to add personnel case code, as follows:

<template>
    <div>
         <el-select v-model="value" placeholder="请选择添加人员">
            <el-option
            v-for="item in options"
            :key="item.name"
            :label="item.name"
            :value="item.name">
            </el-option>
        </el-select>
        <el-button  @click="addPerson">添加</el-button>
        <el-button  @click="rest">还原</el-button>
        <el-table
            :data="filterTable"
            :border='true'
            style="width: 100%;marginTop:10px">
             ... 
            </el-table-column>
        </el-table>
        <h3 style="marginTop:10px;">此时表格总人数为:{
    
    {
    
    filterTable.length}}</h3>
        <h3 style="marginTop:10px;">此时导航二组件的计算总和为:???</h3>
    </div>
</template>
<script>
export default {
    
    
    data() {
    
    
        return {
    
    
           value:'',
           options: [...],
           tableData: [...],
        }
    },
    computed:{
    
    
        filterTable(){
    
    
          return this.$store.state.filterTable
       },
    },
    mounted(){
    
    
       this.initTable()
    },
    methods:{
    
    
        initTable(){
    
    
            const person = this.filterTable.length == 0 ? this.tableData  :  this.filterTable
             this.$store.commit('RESTPERSON',person)
        },
        addPerson(){
    
    
            const obj = {
    
    
                value:this.value,
                options:this.options
            }
            this.$store.dispatch('addPerson',obj)
        },
        rest(){
    
    
           this.$store.dispatch('restPerson',this.tableData)
        }
    }
}
</script>

Vuex implements data sharing between components

Now even if I don’t introduce it, everyone will use it. Now the data required by the two components has been placed in the state of the warehouse, and you only need to get it directly;

Then we will give them the "???" that has always existed in the two components to get the value;

Get the total number of people in the table in the add personnel component in the calculation total component, as follows:

   ...
   <h3 style="marginBotton:10px;">
      此时导航三组件内总人数为:{
    
    {
    
    filterTable.length}}
   </h3>
   <h3>当前计算的和为:{
    
    {
    
    count}}</h3> 
   ...
    computed:{
    
    
        //只需要引入state中的filterTable属性即可
        ...mapState(['count','filterTable'])
    },
   ...

Add the value to obtain the calculated total in the personnel component, as follows:

 ...
 <h3 style="marginTop:10px;">
     此时表格总人数为:{
    
    {
    
    filterTable.length}}
 </h3>
 <h3 style="marginTop:10px;">此时导航二组件的计算总和为:{
    
    {
    
    count}}</h3>
  ...
    computed:{
    
    
      filterTable(){
    
    
          return this.$store.state.filterTable
       },
       count(){
    
    
          return this.$store.state.count
       },
    },
  ...

As long as the calculation total value count in the navigation 2 calculation component changes, the calculation sum in the navigation 3 adding personnel component also changes accordingly;

As long as the table data of the added personnel component in navigation 3 changes, the total number of people in the component of calculating the total number in navigation 2 will also change; as shown below:

insert image description here

insert image description here
In this way, the sharing of data between components is realized, which is much simpler, and you can also practice like me;

Seven. Vuex modular coding (modules)

In fact, so far, you have basically learned how to use Vuex. Modules just assist us to modularize Vuex, making our code clearer, easier to maintain and develop, and improving development efficiency;

Think about it. At present, we only have two components that need to share the array. It seems that there is no problem. Similarly, if there are more than a dozen components, dozens of components also need to share data. Should we put all the shared state and changed business logic? Is it all written in one state, mutations and actions? You can imagine that it must be very messy. What should I do? There are modules;

store modularity

If you want to use modular coding, the code writing in the store will change, and the API introduced by the component will not change, but the writing method will also be different;

First of all, let's divide the store into modules. Currently we have two components. The state, mutations and actions of each component are independent, so we can split the two modules:

Create a count.js file under the store folder. This file only belongs to the status and business logic of calculating the total. Finally, remember to expose it, as follows:

const countOptions = {
    
    
   //这里添加此属性,是为了后面使用map辅助函数简写时可以找到该模块
    namespaced: true,
    state: {
    
    
        count:0,
    },
    getters:{
    
    
      multipleCount(state){
    
    
         return state.count * 10
      }
    },
    mutations: {
    
    
      JIA(state,count){
    
    
          state.count += count
      },
      JIAN(state,count){
    
    
	      state.count -= count
	      if(state.count <= 0) state.count = 0
      },
    },

    actions:{
    
    
      asyncJia(context,value){
    
    
	      return new Promise((resolve,reject) => {
    
    
	          setTimeout(() => {
    
    
	            context.commit('JIA',value)
	            resolve()
	          },1000)
	      })  
      },
      oddJia({
     
     commit,state},value){
    
    
	      if(state.count%2 !== 0){
    
    
	          commit('JIA',value)
	       }
      },
    },
}
export default countOptions

Create an addPerson.js file under the store folder. This file only belongs to the status and business logic of adding a person, and will be exposed at the end, as follows:

import {
    
    message} from 'element-ui'
const addPersonOption = {
    
    
    namespaced: true,
    state: {
    
    
        filterTable:[]
    },
    mutations: {
    
    
      ADDPERSON(state,person){
    
    
          state.filterTable.push(...person)
      },
     //这个重置方法本不需要,只是为了组件使用commit
     //dispatch('restPerson')就可以实现,这里为了下面讲解知识点而用
      RESTPERSON(state,person){
    
    
        state.filterTable = []
        state.filterTable.push(...person)
      }
    },
    actions:{
    
    
      addPerson({
     
     commit,state},obj){
    
    
	       var isHave = true
	       state.filterTable.forEach( e => {
    
    
	           if(e.name == obj.value)  isHave = false
	       })
	       if(!isHave){
    
    
	           message({
    
    
	               message: '人员已添加!',
	               type: 'warning',
	               duration:1000
	           })
	           return
	       }  
	       var person =  obj.options.filter( item => {
    
    
	         return item.name == obj.value
	       })
	       commit('ADDPERSON',person)
      },
      restPerson({
     
     commit,state},value){
    
    
	        state.filterTable = []
	        commit('ADDPERSON',value)
      }
    },
}
export default addPersonOption

Introduce the above two module components in the store/index.js file and hang them into the following modules, as follows:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

import countOptions  from './count'
import addPersonOption from './addPerson'

const store =  new Vuex.Store({
    
    
  modules:{
    
    
    countOptions,
    addPersonOption
  }
})
export default store

In this way, it is divided into modules for development, isn’t it, it’s much clearer;

Modular component calls

Seeing this, I don’t know if you have noticed that I use the map function call method in the total count component; I use the this.$store.xx call method in the add personnel component; the reason for this is to use it now When modularizing, I will introduce to everyone how to introduce the API under the module;

map helper function

Namespace (namespaced) + a simple way of writing the map auxiliary function to call, the way of writing is as follows;

The call to the mapState function is changed to:

    computed:{
    
    
        ...mapState('countOptions',['count']),
        ...mapState('addPersonOption',['filterTable'])
    },

The call to the mapGetters function is changed to:

    computed:{
    
    
        ...mapGetters('countOptions',['multipleCount']),
    },

The call to the mapMutations function is changed to:

methods:{
    
    
     ...mapMutations('countOptions',['JIA','JIAN']),
 }

The call to the mapActions function is changed to:

methods:{
    
    
    ...mapActions('countOptions',['oddJia','asyncJia']),
 }

this.$store.xxx

Get the modular states method, add the module name after the state, as follows:

computed:{
    
    
   filterTable(){
    
    
      return this.$store.state.addPersonOption.filterTable
   },
   count(){
    
    
      return this.$store.state.countOptions.count
   },
},

To obtain the modular mutations method, add "module name +/" before the mutation function name, as follows:

   methods:{
    
    
       initTable(){
    
    
            var person = this.filterTable.length == 0 ? this.tableData  :  this.filterTable
            this.$store.commit('addPersonOption/RESTPERSON',person)
        },
   }

In order to understand the calling method of obtaining modular getters, we add a getters method to the addPersonOption module of Vuex to obtain the name of the first person in the form, and the component call is displayed. The code is as follows:

 getters: {
    
    
      onePersonName(state){
    
    
         return state.filterTable[0].name
      }
 },
 computed:{
    
    
       onePersonName(){
    
    
           return this.$store.getters.['addPersonOption/onePersonName']
       }
  }

Get the modular actions method, as follows:

 methods:{
    
    
     addPerson(){
    
    
          var obj = {
    
    
              value:this.value,
              options:this.options
          }
          this.$store.dispatch('addPersonOption/addPerson',obj)
      },
      rest(){
    
    
          this.$store.dispatch('addPersonOption/restPerson',this.tableData)
      }
 }

Let me show you the demo again. After the modification, the function works normally! Perfect! , the figure is as follows:

insert image description here
insert image description here

8. Summary

Well, the above is all the knowledge points about Vuex, because I recently watched the video of Shang Silicon Valley Vue again. For practice and summary, I wrote this blog about Vuex with nearly 18,000 words. It should be very detailed and very detailed. !

If you like it, you can bookmark it, I hope it can help you, thank you for browsing!

Guess you like

Origin blog.csdn.net/qq_44182284/article/details/125460217