Vuex explained in detail from shallow to deep

foreword

When learning Vue, we often involve communication between components. There are many known communication methods between components, such as: parent-child communication using props, communication between multiple sub-components through the parent component, communication between sub-components using custom events (using refs is also a way), and event bus.

At present, the event bus is a very common method, but it will be troublesome if there are too many event buses when doing projects, and the code is easy to mess up.

In this section, we will introduce a simpler way to realize communication between components - using vuex, the advantage of this method over the above-mentioned method is that using vuex, all components can manipulate the same data together, This avoids the trouble of communication and passing values.

One, understand Vuex

1.1 What is Vuex

Vuex is a Vue plug-in that implements centralized state (data) management in Vue. It performs centralized management (reading and writing) on ​​the shared state of multiple components in Vue applications. It is also a communication method between components and is applicable communication between arbitrary components.

The keywords we can extract from the above paragraph are:
state (data), management, plugins

These three words are more critical. Among them, the relationship between state and data will be explained later; as for management and plug-ins, as can be seen from the above concepts, Vuex is actually a plug-in for state management.

Therefore, our first impression of Vuex can be: a plugin that can be used to manage state (data) in Vue.

1.2 Overview of Vuex

Vuex does not belong to any component, but its internal data can share data. Each component can manipulate internal data with the help of related APIs.

The schematic diagram is as follows:
insert image description here

1.3 The benefits of Vuex unified state management

Ability to centrally manage shared data in Vuex, easy to develop and maintain later;

It can efficiently realize data sharing between components and improve development efficiency.

The data stored in Vuex is responsive and can actually keep the data in sync with the page.

1.4 When to use Vuex

Under normal circumstances, only the data shared between components is necessary to be stored in vuex. For the private data in the component, it is still stored in the data of the component itself.

Second, the configuration of Vuex

2.1 Installing vuex dependent packages and vuex version issues

In Vue2, we use the vuex3 version; in Vue3, we use the vuex4 version. Otherwise, an error may occur.

The author uses vuex3 here:

npm i vuex@3

2.2 Import vuex package

After downloading vuex, it is also introduced above that vuex is a plug-in, so we need to introduce and register it in main.js:

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

2.3 Create a store object

Here we first introduce the following store objects: store is translated as a warehouse. store is used for state management in vuex. The state can also be understood as data.

store is a very important part of vuex.

We need to write a js file in which store objects and related codes are placed:

insert image description here

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

export default new Vuex.Store({
    
    
    state: {
    
    },
    mutations: {
    
    },
    actions: {
    
    }
})

The properties inside the store will be explained one by one later, but configuration is required at the beginning.

2.4 Mount store in main.js

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

Vue.config.productionTip = false

new Vue({
    
    
  render: h => h(App),
  store
}).$mount('#app')

Here, I want to explain to readers why vuex is introduced and registered in store instead of main.js: first we need to know,Be sure to use Vue.use(Vuex) before creating a store instance, and when the js code is compiled, the ones starting with import will be compiled first. In other words, if you put them all in main.js, the store instance must be created first, and then vuex is registered. But this does not comply with the rules, and an error will be reported:
Uncaught Error: [vuex] must call Vue.use(Vuex) before creating a store instance

Three, the core concept of Vuex

This section will focus on a small demo to explain the core concepts in Vuex to readers.

3.1 demo

The case is very simple, I set a number as count, and set up two components, one component is used to add and add the count, and the other is used to subtract and subtract the count. The two components jointly manipulate a count.

In my code, I set up two components, Jiafa and Jianfa, and put them in the App, which is what our demo looks like at the beginning.
insert image description here
insert image description here
Next, I will focus on the above case and complete the case step by step to tell readers about the relevant knowledge of Vuex.

3.2 State

State provides the only public data source in Vuex. All shared data must be agreed to be stored in the State of the Store.

In the initial configuration, we have configured the State property in the Store object. Now, just put the data count we need to share in the state.
insert image description here
One feature of Vuex is:shared. Now, we put the data in the state, and we can share it. Components can access the internal data in State by accessing State.

this.$store.state.全局数据名称

Access in the Jiafa component:
insert image description here
The effect is as follows:
insert image description here
The above has successfully implemented the component to access public data. In template syntax, just use $store.state.count. However, if it is written like this everywhere, the code will look complicated and does not conform to the code specification of Vue. So, a new way appeared, that is mapState.

3.2.1 mapState function

mapState is a function in vuex, which can simplify our code for getting data from state.

We need to introduce this function before using it. Because the component is using simplification, we have to introduce it in the component. We just used the first method to get the count in the addition component, so now we try the second method in the subtraction component.

The first step is to introduce the mapState function:
insert image description here
the second step is to use the mapState function.
The mapState function can simplify the amount of code for us, and its essence is actually acomputed property, so the use of this function should be placed in the calculated property, and the data that needs to be simplified can be directly put into the mapState function.Here we need to add three points, the expansion operator, which means to map the data inside to the computed properties of the current component.
insert image description here
After doing all this, just throw the count into the interpolation syntax:
insert image description here
the effect is as follows:
insert image description here

3.3 Mutation

3.3.1 The wrong way to achieve addition and subtraction that leads to Mutation

So far, we have seen two ways to get data from state. Now that the data is obtained, we also have the ability to manipulate the data. For example, I now want to realize the self-increment of the count, and set the click event directly on the basis of the obtained data:
insert image description here
However, == In Vuex, components are not allowed to directly modify the data in the Store. == So this way is very illegal. So how should we operate on the data? This is what I need to introduce below.

3.3.2 Use of Mutations

Mutation is used to change the data in the Store.

In Vuex, the data in the Store can only be changed through mutation, and the data in the Store cannot be directly manipulated.

And it will be a little cumbersome to operate in this way, but == can centrally monitor data changes. If we use the previous wrong writing method to modify the data every time, it will not be conducive to the maintenance of the data later.

The above is the role of Mutation and the reason why Mutation is used.

Below, we will introduce how to use Mutation to modify the data.

In the Store configuration file, we first need to configure Mutation, and configure functions related to operating data in it.
insert image description here
Now, we need to trigger the mutation in the component. The trigger method is very simple, using the commit function. Use the commit function to call the method in the mutation.

this.$store.commit('add')

insert image description here
Now our component can use addition normally:
insert image description here

3.3.3 Mutation passing parameters

What we just realized is to let the count increase automatically. But now to provide new requirements, I am not sure to let the count increase by itself, I want to add five to the count. In this case, you need to pass parameters to tell Mutation how much to add to the count.

So the content of this section is to tell readers how to pass parameters when using Mutation.

First, the mutation is still configured:

insert image description here
Then, trigger the mutation, button binding event:
insert image description here
and then use commit to trigger the mutation:
insert image description here
the use in the component is actually similar to the way of passing parameters in general functions.

3.3.4 mapMutations

After learning state, we learned mapState, which successfully solved the problem of cumbersome data acquisition codes. Now we learn mapMutations for the same purpose, in order to make the code look more concise and clear at a glance.

Now, let's implement the subtraction function

The first step is still to configure mutation:
insert image description here
Next, we need to use sub in the component. Still first bind the button to the event:
insert image description here
Then, we need to introduce mapMutations:
insert image description here
Then, call mapMutations, similar to the previous principle, still need to write the expander, and call its internal sub function.
insert image description here
Note here that...mapMutations must be placed in methods, not in computed properties. Because our subhandle needs to use it.

Next, we use a similar method to implement parameter passing:

It is still configured in the mutations first:
insert image description here
then bind the button to the event:
insert image description here
finally call:
insert image description here

3.4 Advanced version demo

Above, we have implemented the basic operations on count: read count, and perform addition and subtraction operations on count;

Now, put forward an advanced version of the request: If you want to click the button, wait for one second and then add one to the count' value.

It is obvious here that we need a timer, and the timer is counted as an asynchronous task.

Readers can try to add a timer in the function of mutations. But the final result is that the page changes, but there is no way to observe the change of count in Vue's browser debugger.

Asynchronous operations cannot be performed in mutations, and vuex cannot recognize them normally.

What if we want to do asynchronous operations? Subsequent content will focus on this issue.

3.5 Action

In Vuex, Action is used to handle asynchronous tasks.

If you change data through asynchronous operations, you must pass Action instead of Mutation.But in the Action, it is still necessary to indirectly change the data by triggering the Mutation.

3.5.1 Use of Actions

First of all, actions are still configured in the store file. There is a function inside, and a timer is written inside the function. In actions, the function in mutations still needs to be called through commit, so we give addAsync a parameter and let this parameter call commit .Note here that data cannot be modified in actions, only functions defined in mutations have the right to modify data.

insert image description here

Here we have defined actions, now we need to use it in the component.

First, bind an event to the button:
insert image description here
Then, to trigger the timer in addasync, we need to trigger Actionin.We learned earlier that we need to use commit to trigger functions in mutations, and we need to use dispatch to trigger actions.
insert image description here

3.5.2 How to carry parameters when using actions

When we wrote the addAsync function just now, we operated add internally by calling commit. Now what we want to achieve is to add five to addasync. In connection with the previous explanation, you can be keenly aware that when using actions here, you need to carry parameters, and it is still delayed for one second before adding.

First of all, it is still writing actions, here we call the addfive function we just wrote:
insert image description here

Then it is used in the component, still setting a button and binding events to the button:

insert image description here

Then write the event addasyncfive:
insert image description here
Finally, it can be used normally.

3.5.3 mapActions

Similar to the previous ones, mapActions is the second way to trigger actions.

This time we will implement the operation of subtracting count by 5 with a delay of one second in the subtraction.

The first step is still to configure actions

insert image description here

Then use it in the component, still introduce the mapActions function first, and use it to declare in the methods, don't forget the expander:
insert image description here
then set the button, and write the binding event of the button:
insert image description here

insert image description here

3.6 Getter

Getter is used to process the data in the Store to form new data, which is similar to Vue's calculated properties.

If the Store data changes, the Getter data will also change.

But Getter will not modify the data of State, it only acts as a wrapper.

So this section describes the last core concept of vuex: Getter.

3.6.1 Use of Getters

The first is the configuration of the Getter.

A getter is defined here:
insert image description here
Then there are two ways to use getters, the first one:

this.$store.getters.名称

Used in App:
insert image description here
It can be displayed normally:
insert image description here

3.6.2 mapGetters

It is still introduced first
insert image description here
and placed in the computed property:
insert image description here
it can be used at the end:
insert image description here
the effect remains the same:
insert image description here

Fourth, the code part

main.js

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

Vue.config.productionTip = false

new Vue({
    
    
  render: h => h(App),
  store
}).$mount('#app')

app.vue

<template>
  <div>
    <Jiafa></Jiafa>
    <Jianfa></Jianfa>
    <!-- {
    
    {
    
     $store.getters.showNum }} -->
    {
    
    {
    
     showNum }}
  </div>
</template>

<script>
import Jiafa from '@/components/Jiafa.vue'
import Jianfa from '@/components/Jianfa.vue'
import {
    
     mapGetters } from 'vuex';
export default {
    
    
  name: 'App',
  components: {
    
    Jiafa, Jianfa},
  computed: {
    
    
    ...mapGetters(['showNum'])
  },
}
</script>

<style>

</style>

store-index.js

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

export default new Vuex.Store({
    
    
    state: {
    
    
        count: 0
    },
    mutations: {
    
    
        add(state) {
    
    
            //加加
            state.count++
        },
        addfive(state, i) {
    
    
            // 加五
            state.count += i;
        },
        sub(state) {
    
    
            //减减
            state.count--
        },
        subfive(state, i) {
    
    
            // 减五
            state.count -= i
        }
    },
    actions: {
    
    
        addAsync(context) {
    
    
            setTimeout(() => {
    
    
                context.commit('add')
            }, 1000)
        },
        addAsyncfive(context, i) {
    
    
            setTimeout(() => {
    
    
                context.commit('addfive', i)
            }, 1000)
        },
        // 减减延迟1s
        subAsync(context) {
    
    
            setTimeout(() => {
    
    
                context.commit('sub')
            }, 1000)
        },
        // 减5延迟1秒
        subAsyncfive(context, i) {
    
    
            setTimeout(() => {
    
    
                context.commit('subfive', i)
            }, 1000)
        },
    },
    getters: {
    
    
        showNum(state) {
    
    
            return '当前最新的数量是['+ state.count + ']';
        }
    }
})

Jiafa

<template>
    <div>
        <div>当前最新的count的值为:{
    
    {
    
     $store.state.count }}</div>
        <button @click="add">+1</button>
        <button @click="addfive()">+5</button>
        <button @click="addasync">延迟一秒后+1</button>
        <button @click="addasyncfive(5)">延迟一秒后加五</button>
    </div>
</template>

<script>
export default {
    
    
    name: 'Jiafa',
    methods: {
    
    
        add() {
    
    
            this.$store.dispatch('addAsync')
            this.$store.commit('add')
        },
        addfive() {
    
    
            this.$store.commit('addfive', 5)
        },
        // 延迟一秒后再加
        addasync() {
    
    
            this.$store.dispatch('addAsync')
        },
        addasyncfive(i) {
    
    
            this.$store.dispatch('addAsyncfive', i)
        }
    }
}
</script>

<style></style>

Jianfa

<template>
    <div>
        <div>当前最新的count的值为:{
    
    {
    
     count }}</div>
        <button @click="subhandle">-1</button>
        <button @click="subi(5)">-5</button>
        <button @click="subasync">延迟一秒减一</button>
        <button @click="subasyncfive(5)">延迟一秒减5</button>
    </div>
</template>

<script>
// 引入mapState
import {
    
    mapMutations, mapState, mapActions} from 'vuex'
export default {
    
    
    name: 'Jianfa',
    computed: {
    
    
        ...mapState(['count']),
    },
    methods: {
    
    
        ...mapMutations(['sub', 'subfive']),
        ...mapActions(['subAsyncfive', 'subAsync']),
        subhandle() {
    
    
            this.sub()
        },
        subi(i) {
    
    
            this.subfive(i)
        },
        //延迟1s减一
        subasync() {
    
    
            this.subAsync()
        },
        subasyncfive(i) {
    
    
            // 延迟1s减5
            this.subAsyncfive(i)
        }
    }                                                                     
}
</script>

<style></style>

postscript

The above is the core concept and basic use of Vuex. Hope this helps readers! If you have any questions, just comment in the comment area.

Welcome to pay attention, follow-up will bring more exciting content!

Guess you like

Origin blog.csdn.net/zxdznyy/article/details/128899867