Abstract: In simple terms, Vuex is a mechanism to achieve global state (data) management of components, which can easily realize data sharing between components.

This article is shared with huawei cloud community “Vuex State Machine Quick Understanding and Application”, originally written by: Northern Lights Night.

I. Quick Recognition concept:

1. How to share data between components:

There are usually the following ways:

1. Transfer value from parent to child: V-bind;

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

3. Share 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 global state (data) management of components, facilitating data sharing among components.

3. Advantages of using VUEX:

1. Centralized management of shared data in VUEX, easy to develop and maintain.

2. Can efficiently realize data sharing between components and improve development efficiency.

3. The data stored in VUEX is responsive and can be synchronized with the page in real time.

4. Resolved non-parent component messaging (storing data in state).

5. Reduced the number of AJAX requests, 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' vuue. Use (Vuex) const store = new Vuex.Store({//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 small counter case, from the case with the concept can be faster to use vuEX. 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 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>count values are: </p> <button>+1</button> </div> </template> <script> export default{ data() { return { } }, } </script>Copy the code

Subcomponent Reduce.vue initial code:

<template> <div> <p>count values are: </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>count values are: {{this.$store.state.count}}</p> <button>+1</button> </div> </templateCopy 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 values are: {{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:

Open mutations: open mutations: open mutations: open mutations: open mutations: open mutations: open mutations: open mutations: open mutations: open mutations: open mutationsCopy 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>count values are: {{this.$store.state.count}}</p> <button @click="btnAdd">+1</button> </div> </template> <script> export default{ data() { This.code.store.mit ('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: AddN (state,n){state.count+= n}}})Copy the code

The corresponding component calls with an argument:

() {btnAdd2() {use this. Codestore.mit ('addN',6)}}Copy the code

2.3 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: Add (state){state.count++}, sub(state){state.count--}}})Copy the code

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

<template> <div> <p>count values are: {{count}}</p> <button @click="btnSub">-1</button> </div> </template> <script> import {mapState,mapMutations} from 'vuex' export default{ data() { return { } }, computed: { ... MapState (['count'])}, methods: {// mutation subfunction... MapMutations (['sub']), // call the sub function 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: Add (state){state.count++}, sub(state){state.count--}}, The addAsync () function will execute the add (actions) function from mutation after 1 second: {addAsync(context) {setTimeout(()=>{// mutation must be triggered by context.mit () context.mit ('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>count values are: {{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, 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: AddN (state,n){state. Count += n}}, actions: AddNAsync (context,n) {setTimeout(()=>{context.com MIT ('addN',n)},1000)}}Copy the code

The corresponding component calls with an argument:

Methods: {btnAdd2() {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: Add (state){state.count++}, 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 values are: {{count}}</p> < button@click ="btnSub">-1</button> </div> </template> <script> import {mapState,mapActions} from 'vuex' export default{ data() { return { } }, computed: { ... MapState (['count'])}, methods: { MapActions (['subAsync']), // To subtract, 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 'count+1 :${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 > / / incoming components import the Add the from './components/ add. vue' import Reduce from './components/ reduce. vue' import {mapGetters} from 'vuex' export default { name: 'App', data() { return { } }, components: { 'my-add': Add, 'my-reduce': Reduce}, // Introduce getter computed: {... mapGetters(['showNum']) } } </script>Copy the code

Look, the same effect:

Click to follow, the first time to learn about Huawei cloud fresh technology ~