This is my 25th day of the Gwen Challenge

I. Quick Recognition concept:

1. How to share data between components:

There are usually the following ways:

  1. Parent to child: V-bind;

  2. Value from child to parent: V-ON event binding;

  3. Sharing data between sibling components: EventBus;

What is vuex:

  1. Officially, 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.

  2. To put it simply, Vuex is a mechanism for managing global state (data) of components and facilitating data sharing between components.

3. Advantages of using VUEX:

  1. Centralized management of shared data in VUEX for easy development and maintenance.
  2. It can efficiently realize data sharing between components and improve development efficiency.
  3. The data stored in VUEX is responsive and keeps the data in sync with the page in real time.
  4. Resolved non-parent component messaging (storing data in state).
  5. AJAX requests are reduced, and some scenarios can be retrieved directly from state in memory.

In general, only data shared between components is necessary to be stored in VUEX. For private data in the component, it is not necessary and can still be stored in the component’s own data. Of course, you can store them all in VUEX if you want.

Ii. Basic Use:

1. Install dependency packages:

npm install vuex --save
Copy the code

2. Import dependency packages:

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

Vue.use(Vuex)
Copy the code

Create a store object:

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

Vue.use(Vuex)

const store = new Vuex.Store({
//state stores globally shared data
  state: {
    count: 0}})Copy the code

4. Mount store object to vue instance:

new Vue({
  el: '#app',
  store
})
Copy the code

At this point, all components can get data from the Store.

Iii. Create project:

Here is the process for creating a VUE project, followed by examples:

(1) Open the CMD window and enter Vue UI to open the visual panel of VUE:

(2) Select the path of new project:

(3) Naming:

(4) Manually select the configuration, note that vue2 version is used: (5) Create:

(6) Next Step:(7) Create successfully, go to the corresponding directory to open VScode and start programming:(8) Operating Projects:

Iv. Explain the premise:

Premise (note) : Write a counter mini case, from which the concept can be used faster. So the code portion of the core concept below is based on this small example. Goal: Write two child components that have a common count value. In the parent component, one component implements a click that reduces count by 1 and one component implements a click that increases count by 1.

Parent component app.vue initial code:

<template>
  <div id="app">
       <my-add></my-add>
       <p>--------------------</p>
       <my-reduce></my-reduce>
  </div>
</template>

<script>
// Import components
import Add from './components/Add.vue'
import Reduce from './components/Reduce.vue'
export default {
  name: 'App'.data() {
    return{}},components: {
    'my-add': Add,
    'my-reduce': Reduce
  }

}
</script>
Copy the code

The initial code for the child add.vue:

<template>
    <div>
        <p>The count value is:</p>
           <button>+ 1</button>
    </div>
 
</template>
<script>
  export default{
      data() {
          return{}}},</script>
Copy the code

Subcomponent Reduce.vue initial code:

<template>
    <div>
         <p>The count value is:</p>
           <button>- 1</button>
    </div>
</template>
<script>
  export default{
      data() {
          return{}}},</script>
Copy the code

The initial code for the store object is:

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count: 0}})Copy the code

Initial effect:

V. Core Concepts:

1. The state:

Officially, it reads as follows: Vuex uses a single state tree — yes, a single object that contains all application-level states. At this point it exists as a “unique data source (SSOT)”. This also means that each app will contain only one Store instance.

Simply put, State provides a single common data source, and all shared data is stored in the Store State.

1.1 The first way to access state in a component:

Enter the following command directly from the component:

This.$store.state. The name of the referenced dataCopy the code

As referenced in the Add.vue subcomponent:

<template>
    <div>
        <p>{{this.$store.state.count}}</p>
           <button>+ 1</button>
    </div> 
</template>// The following part of the code is unchanged as before, so it is omittedCopy the code

The value of count is 0:

1.2 Second way to access state in a component:

(1) Import mapState function from VUEX as needed

import { mapState } from 'vuex'
Copy the code

(2) Map global data needed by the current component to computed attributes of the current component using the mapState function imported just now:

computed: { ... mapState([count]) }Copy the code

Fact: Computed is used to monitor self-defined variables, which are not declared in data, but defined directly in computed, and then used for two-way data binding on the page to display results or for other processing purposes;

As referenced in reduce.vue subcomponents:

<template>
    <div>
         <p>Count is: {{count}}</p>
           <button>- 1</button>
    </div>
</template>
<script>
import {mapState} from 'vuex'
  export default{
      data() {
          return{}},computed: {
         ...mapState(['count'])}}</script>
Copy the code

Count = 0;

2. The mutation:

Officially, the only way to change the state in Vuex’s store is to commit mutation. Mutations in Vuex are very similar to events: each mutation has a string event type (type) and a callback function (handler). This callback is where we actually make the state change, and it accepts state as the first argument.

Mutation is used to change data in a Store. ① Only Store data can be changed by mutation, and data in Store can not be manipulated directly. (2) Although the operation is a little more complicated in this way, all data changes can be monitored centrally.

For example, to increments count by one, define a function that increments by one in the preceding modments. If the subcomponent wants to use mutation, the subcomponent directly introduces mutation and calls the corresponding function.

As follows, the subcomponent of Add.vue needs to realize the auto-increment function: first, define a function Add that can realize the auto-increment in the mutations in the state machine:

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    // Increment the function by 1
    add(state){
      state.count++
    }
  }
})
Copy the code

2.1 The first way to trigger mutation:

The add. vue subcomponent will bind the button click event and trigger mutation:

<template>
    <div>
        <p>{{this.$store.state.count}}</p>
           <button @click="btnAdd">+ 1</button>
    </div>
 
</template>
<script>
  export default{
      data() {
          return{}},methods: {
          btnAdd() {
              // The first way to introduce mutation is to trigger the add function
              this.$store.commit('add')}}}</script>
Copy the code

See the effect to achieve the click autoincrement:

2.2 Triggering mutation and transferring parameters:

Of course, when a component calls a mutation function, it can also pass arguments. For example, there is an increment function, but increment depends on the arguments passed in the call:

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    // The first parameter must be state, and the second parameter is passed in
    // a function that increments n
    addN(state,n){
      state.count+= n
    }
  }
})
Copy the code

The corresponding component calls with an argument:

  methods: {
          btnAdd2() {
              // The addN function is triggered by mutation
              // Add 6
              this.$store.commit('addN'.6)}}Copy the code

2.1 The second way to trigger mutation:

(1) Import the mapMutations function from VUEX on demand

import { mapMutations } from 'vuex'
Copy the code

(2) Through the imported mapMutations function, map the required mutations function to the methods of the current component:

methods: { ... mapMutations(['add'.'addN'])}Copy the code

Actual combat, realize the functional requirements of Reduce. Vue component click autosubtract 1:

State machine add decrement function:

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    // Increment the function by 1
    add(state){
      state.count++
    },
    // the function decrement by 1
    sub(state){
      state.count--
    }
  }
})
Copy the code

Reduce. Vue components Reduce by 1 by clicking the button:

<template>
    <div>
         <p>Count is: {{count}}</p>
           <button @click="btnSub">- 1</button>
    </div>
</template>
<script>
/ / import
import {mapState,mapMutations} from 'vuex'
  export default{
      data() {
          return{}},computed: {
         ...mapState(['count'])},methods: {
          // the sub function in the mutation mapping. mapMutations(['sub']),
          // To decrement, call sub
          btnSub(){
             this.sub()
          }
      }
  }
</script>
Copy the code

See the effect:

3. The Action:

Now, the case in the fourth point is complete, and we have implemented the increment and decrement. Now we need to improve the case, and we need to click the button for a second and then increment and decrement. How to do this? Mutation does not support async operation, but does not support async operation. For example, mutation does not support async operation.

Action can contain any asynchronous operation, so it is used to handle asynchronous tasks. The Action commits mutation rather than a direct state change. Remember that it does not modify the data in state directly, only mutation can. That is, if the data is changed by an asynchronous operation, it must be changed through an Action instead of Mutation, but the data must be changed indirectly by triggering Mutation in the Action.

Define the Action in the state machine:

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    // Increment the function by 1
    add(state){
      state.count++
    },
    // the function decrement by 1
    sub(state){
      state.count--
    }
  },
  Add (mutation) {// add (mutation) {// add (mutation)
   actions: {
    addAsync(context) {
      setTimeout(() = >{
      // mutation must be triggered by context.mit ()
         context.commit('add')},1000)}}})Copy the code

The Action function accepts a context object with the same methods and properties as the store instance, so you can commit a mutation by calling context.mit.

3.1 The first way to trigger an Action:

Change component add.vue code to introduce Action to implement asynchronous increment operation.

<template>
    <div>
        <p>{{this.$store.state.count}}</p>
           <button @click="btnAdd">+ 1</button>
    </div>
 
</template>
<script>
  export default{
      data() {
          return{}},methods: {
          btnAdd() {
              The first way to introduce an Action is to trigger the addAsync function
              // Dispatch is specifically used to call the action function
              this.$store.dispatch('addAsync')}}}</script>
Copy the code

See the effect, realize 1 second after the autoincrement:

3.2 Triggering an Action Asynchronous Task and passing parameters:

Of course, when a component calls an action function, it can also pass arguments. For example, let’s have an increment function that executes after a second is clicked, but the increment depends on the arguments passed in the call:

Definition:

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
   // The first parameter must be state, and the second parameter is passed in
    // a function that increments n
    addN(state,n){
      state.count+= n
    }
  },
   actions: {
    // the addN function of the mutation has an argument n
    addNAsync(context,n) {
      setTimeout(() = >{
         context.commit('addN',n)
    },1000)}}})Copy the code

The corresponding component calls with an argument:

  methods: {
          btnAdd2() {
              Call the dispatch function
              // When the action is triggered, the parameter is set to 6, indicating an increment of 6
              this.$store.dispatch('addNAsync'.6)}}Copy the code

3.3 Second way to trigger an Action:

(1) Import mapActions functions from VUEX as needed

import { mapActions } from 'vuex'
Copy the code

(2) Map the required actions function to the current component’s methods by importing mapActions function just now:

methods: { ... mapActions(['add'.'addN'])}Copy the code

To realize the functional requirements of reducing. Vue components by 1 after clicking:

Define subAsync in actions as decrement after one second:

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    // Increment the function by 1
    add(state){
      state.count++
    },
    // the function decrement by 1
    sub(state){
      state.count--
    }
  },
   actions: {
    addAsync(context) {
      setTimeout(() = >{
         context.commit('add')},1000)},subAsync(context) {
      setTimeout(() = >{
         context.commit('sub')},1000)}}})Copy the code

Change reduce. vue code to achieve the following functions:

<template>
    <div>
         <p>Count is: {{count}}</p>
           <button @click="btnSub">- 1</button>
    </div>
</template>
<script>
/ / import
import {mapState,mapActions} from 'vuex'
  export default{
      data() {
          return{}},computed: {
         ...mapState(['count'])},methods: {
          // map the function in the Action. mapActions(['subAsync']),
          // To decrement, call subAsync
          btnSub(){
             this.subAsync()
          }
      }
  }
</script>
Copy the code

See the effect:

4. The Getter:

Getters are used to process data in a Store to form new data. Note that it does not modify the data in state. (1) Getters can form new data after processing existing data in Store, similar to Vue calculation properties. ② When the data in the Store changes, the data in the Getter also changes.

For example, there is a getter function that returns the current count+1:

export default new Vuex.Store({
  state: {
    count: 0
  },
 getters: {
    showNum(state){
      return'The current count value plus 1 is:${state.count+1}`}}})Copy the code

4.1 The first way to trigger getters:

this. $store. Getters. NameCopy the code

Display in app.vue component:

<template>
  <div id="app">
       <my-add></my-add>
       <p>--------------------</p>
       <my-reduce></my-reduce>
       <p>--------------------</p>
       <h3>{{this.$store.getters.showNum}}</h3>
  </div>
</template>
Copy the code

Effect:

4.2 Second way to trigger getters:

(1) Import mapGetters functions from VUEX as needed

import { mapGetters } from 'vuex'
Copy the code

(2) Map global data needed by the current component to computed attributes of the current component using the mapGetters function imported just now:

computed: { ... mapGetters(['showNum'])}Copy the code

Again in app.vue:

<template>
  <div id="app">
       <my-add></my-add>
       <p>--------------------</p>
       <my-reduce></my-reduce>
       <p>--------------------</p>
       <h3>{{showNum}}</h3>
  </div>
</template>

<script>
// Import components
import Add from './components/Add.vue'
import Reduce from './components/Reduce.vue'
// Import mapGetters
import {mapGetters} from 'vuex'
export default {
  name: 'App'.data() {
    return{}},components: {
    'my-add': Add,
    'my-reduce': Reduce
  },
  / / into the getter
  computed: {
    ...mapGetters(['showNum'])}}</script>
Copy the code

Look, the same effect:

Vi. Summary:

See you next time ~