Introduction, Installation and initialization

What is a vuex

VueX is a state management tool suitable for use in Vue project development. Vue provides a unified management tool — VueX — for these values that are frequently used by multiple components. In a Vue project with VueX, we just need to define these values in the VueX to be used in the components of the entire Vue project.

How do I install vuex

NPM install

npm i vuex -s
Copy the code

How to use Vuex

Create index.js in a new store folder under the root of your project

The project’s SRC folder looks like this

│ App. Vue │ main. Js │ ├ ─ assets │ logo. The PNG │ ├ ─ components │ HelloWorld. Vue │ ├ ─ the router │ index. The js │ └ ─ store index, jsCopy the code

In the store.js file, introduce vuex and use vuex, noting that the variable names are capitalized Vue and vuex

//store.js
import Vue from 'vue'
import Vuex from 'vuex'
/ / mount Vuex
Vue.use(Vuex)
// Create a VueX object
const store = new Vuex.Store({
    state: {// The stored key-value pair is the state to be managed
        name:'helloVueX'}})export default store
Copy the code

Mount store into the Vue instance of the current project

//main.js
import store from './store'
new Vue({
  el: '#app',
  router,
  store,  // Just like the router, mount the Vuex instance we created into the vue instance
  render: h= > h(App)
})
Copy the code

Use Vuex in components

For example, in app.vue, we take the name defined in state and display it in the H1 tag

<template>
    <div id='app'>
        name:
        <h1>{{ $store.state.name }}</h1>
    </div>
</template>
Copy the code

Or use it in a component method

methods:{
    add(){
      console.log(this.$store.state.name)
    }
},
Copy the code

Detailed usage methods will be described below

Note: the emergence of vuex is to solve the problem of communication between components, if an action or data does not involve public action, only a single component operations, do not store the status value or function to the vuex, because vuex would make their own mount on all components, whether or not the current component used the contents, so this fact Definitely adds to the performance loss.

The core of VueX

In VUex, there are five basic objects by default:

  • State: Storage state (variable)
  • getters: recompile the data before fetching itstateCompute properties of.
  • 2. mutations: Changes the status, and it’s simultaneous. This is similar to custom events in our component.
  • Actions: Asynchronous operations.
  • modules:storeA child of the module

Split into single files

If the project status and methods too much, the index. The js file will look very bloated and poor maintenance, this time we can state, getters, mutations, the actions into a single file, is helpful to manage

The directory structure looks like this

Store │ │ ├ ─ index. Js │ │ ├ ─ state. The js │ │ ├ ─ getters. Js │ │ ├ ─ mutations. Js │ │ └ ─ actions. JsCopy the code

index.js


import Vue from 'vue';
import Vuex from 'vuex';
import state from './state';
import getters from './getters';
import mutations from './mutations';
import actions from './actions';
Vue.use(Vuex);
export default new Vuex.Store({
  state,
  mutations,
  actions,
  getters,
});
Copy the code

Other files only need export and export

state.js


export default {
  name:'hzw'
};
Copy the code

mutations.js

export default {
 changeName(state, name){ state.name = name; }};Copy the code

getters.js

export default {
 realName(state) {
    return "Name:" + state.name
  },
};
Copy the code

actions.js

export default {
 changeName({ commit }, name) {
        return commit('changeName', name)
    }
};
Copy the code

This makes it look more structured and easier to maintain

The state and the mapState

What is the state

The state (vuex) material data (vue)

Vuex’s state has many similarities with VUE’s data in that it is used to store some data, or state values. These values will be mounted to the bi-directional binding event between the data and the DOM, which triggers dom updates when the value changes.

We declare a state count in state.js, with an initial value of 0, and then print it in the component

// state.js 
export default {
  count:'0'
};
Copy the code
/ / components
<template>
  <div class="hello">
    <h3>{{$store.state.count}}</h3>
  </div>
</template>
Copy the code

The result is shown below

Note: Although state and data have a lot in common, state is generally mounted on computed properties of child components when used, which makes it easier to respond to child components when the value of state changes. If you use data to receive $store.state, you can also receive the value, but since this is a simple assignment, state changes cannot be heard by data in vue. Watch $Store can also solve this problem, but it is a bit troublesome.

So, it’s best to use computed to receive state, as follows, and I’ll show you how to modify state later.

//mutations.js
export default {
  add(state, n = 0) {
    return (state.count += n)
  },
  reduce(state, n = 0) {
    return (state.count -= n)
  }
}
Copy the code
/ / components
<template>
  <div class="hello">
    <h3>{{$store.state.count}}</h3>
    <div>
      <button @click="add(10)">increase</button>
      <button @click="reduce(10)">To reduce</button>
      <div>computed:{{dataCount}}</div>
        <div>data: {{count}}</div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
   data () {
    return {
      dataCount: this.$store.state.count // Receive with data}},computed: {count(){
      return this.$store.state.count // Use computed reception}},methods: {
    add(n){
      this.$store.commit('add',n);
    },
   reduce(n){
      this.$store.commit('reduce',n); }}}</script>
Copy the code

Then we click on the add button and see what happens. What happens

As you can see, values received with data do not respond to updates in a timely manner, as can be done with computed.

Initialization of Props, Methods,data, and computed is done between beforeCreated and created.

What is the mapState

MapState is an auxiliary function of state

What it actually does: When a component needs to fetch multiple states, it can be repetitive and redundant to declare all those states as computed properties. To solve this problem, you can use the mapState helper function to help generate computed properties

How to use it: Import this helper function first.


import { mapState } from 'vuex'
Copy the code

Then you can use mapState in computed

When using auxiliary functions such as mapState, if the names inside the component are the same as those in VUEX, you can abbreviate them to arrays.

//state.js
export default {
    nickname:'Simba'.age:20.gender:'male'
};
Copy the code
//computed
computed: mapState(['nickname'.'age'.'gender'])
// The following code is much more concise
computed: {nickname(){return this.$store.state.nickname}
  age(){return this.$store.state.age}
  gender(){return this.$store.state.gender}
}
Copy the code

If you need to customize a calculated property, you need the expansion operator in ES6:…

data(){
  return{
    count:14}}computed: {   
  value(){
   return "Name:" + this.coount/7
},
  ...mapState(['nickname'.'age'.'gender'])}Copy the code

Getters and mapGetters

What is the getters

Getters: The return value of getters is cached according to its dependencies, and is recalculated only if its dependencies change. This is roughly equal to computed in Vue. You can use getters just as you use computed, but there are differences.

How do I use Getters

Methods in getters take two default arguments

  • stateThe currentVueXThe state object in the object
  • gettersThe currentgettersObject that will be used togettersThe othergetterUse them
//state.js
export default {
  name:'simba'.age:'20'
};
//getters.js
export default {
  // The first argument is state
  realName(state) {
    return "Name:" + state.name
  },
  // The second argument accesses getters
  nameAndAge(state, getters) {
    return "Age." + state.age +";"+ getters.realName
  }
};
Copy the code

How do I access Getters

Access by property

Getters are exposed as store.getters objects, and we can access these values as properties:

store.getters.realNameName :simba
Copy the code

Note that getters are cached as part of Vue’s responsive system when accessed through properties.

Access by method

We can do this by asking getters to return a function. This is useful when querying an array in a store.

state:{
  todos:[
    {
      id:2.text:'... '.done: false}},getters: {
  getTodoById: (state) = > (id) = > {
    return state.todos.find(todo= > todo.id === id)
  }
}
store.getters.getTodoById(2) // -> {id: 2, text: '... ', done: false}
Copy the code

Note that the getter is called every time it is accessed through a method and does not cache the result.

Used in components

In computed, we bind a computed property with this.$store.getters. XXX

/ / components
<template>
  <div class="hello">
    <div>
        <div>{{message}}</div>
        <div>{{message2}}</div>
    </div>
  </div>
</template>
computed:{
   message(){
     return this.$store.getters.realName 
   },
   message2(){
     return this.$store.getters.nameAndAge; }},Copy the code

The results are as follows:

What is a mapGetters

The mapGetters helper function simply maps the getters in the store to local computed properties:

How to use it: Import this helper function first.

import { mapGetters } from 'vuex'
Copy the code

Then you can use mapGetters in computed

computed: { ... mapGetters({message: "realName".message2: "nameAndAge"})},Copy the code

If the name of the evaluated property is the same as the name of getters, you can also use the array abbreviation

computed: { ... mapGetters(["realName"."nameAndAge"])},Copy the code

Mutation and mapMutation

What is a mutation

Mutation is a collection of methods that operate on state data, such as modifying, adding, deleting, and so on. Mutation usually stores some methods to synchronize the modified state.

Note: The only way to change the state in Vuex’s store is to commit mutation.

How to use mutation

Mutations methods all have a default parameter: mutation([state] [,payload])

  • stateThe currentVueXThe object of thestate
  • Payload (parameter that the method passes when it is called)
//state.js
export default {
  name:'Han Zhiwei'
};
//mutations.js
export default {
 changeName(state, name){ state.name = name; }};Copy the code

We need to call mutation like this

this.$store.commit('changeName'.Daniel Wu)
Copy the code

For example, let’s modify the name attribute in the component’s Methods

methods: {
    changeName(name){
      this.$store.commit('changeName',name); }},// Call changeName
mounted(){
  this.changeName(Daniel Wu)}Copy the code

When you need multiple parameter submissions, you can put them in one object

this.$store.commit('changeName', {firstName:'han'.lastName:'zhiwei'})
Copy the code

You can also pass the parameter in another way

this.$store.commit({
    type:'changeName'.payload: {firstName:'han'.lastName:'zhiwei'}})Copy the code

What is a mapMutation

The mapMutation helper function simply maps mutation in store to component methods

How to use it: Import this helper function first.

import { mapMutation} from 'vuex'
Copy the code

You can then use mapMutation in methods


methods: {... mapMutations({changeName:'changeName'})},Copy the code

This code is equivalent to the following


changeName(payLoad){
  this.$store.commit('changeName',payLoad)
}
Copy the code

If the method name is the same as the mutation name, it can be shortened as follows

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

You can also use constants instead of the Mutations event type

Create a new mutation-types. Js file under the Store folder

//mutation-types.js
export const ADD_AGE = 'ADD_AGE'
//mutations.js
import * as types from './mutation-types';
export default {
  [types.ADD_AGE](state, payLoad) {
    state.age += payLoad.number
  }
}
// The js part of the component. mapMutations([types.ADD_AGE]),Copy the code

But this is not very commonly used, it is ok to know this knowledge point

Add or delete members in state

Now that we’ve talked about how to change the value of state, by the way, how to add or remove members of state

Vue. Set Sets the value of a member for an object, or adds it if it does not exist

Vue.set(state,"age".22)
Copy the code

Vue.delete Deletes a member

Vue.delete(state,'age')
Copy the code

The actions and mapActions

What are the actions

Because asynchronous operations are performed directly in the mutation method, data failure may occur. So Actions are provided specifically for asynchronous operations, similar to AXIOS requests, and ultimately to modify the values in state by submitting the mutation method.

How to use Actions

Methods in Actions have two default parameters: Action([context] [,payload])

  • contextContext objects containdispatch commit state getters rootStateYou can usees6The deconstruction assignment of the{ commit }
  • Payload (parameter that the method passes when it is called)

Look at an example of a mutation that modifies the name attribute in state after a second

//state.js
export default {
  name:'Han Zhiwei'
};
//mutations.js
export default {
 changeName(state, name){ state.name = name; }};//actions.js
export default {
 asyncChangeName({ commit } ,name) {
   setTimeout(() = > {
     commit('changeName',name);
  }, 1000); }};Copy the code

We need to call the action this way

this.$store.dispatch('asyncChangeName'.Daniel Wu)
Copy the code

For example, let’s modify the name attribute in the component’s Methods

methods: {
    changeName(name){
      this.$store.dispatch('asyncChangeName',name); }},// Call changeName
mounted(){
  this.changeName(Daniel Wu)}Copy the code

You can also call another action from an action

//actions.js
export default {
 asyncChangeName({ dispatch }) {
   setTimeout(() = > {
     dispatch('anotherAction');
  }, 1000);
  },
 anotherAction(){
   console.log('Another action has been called')}};Copy the code

Action can also pass in state, and rootState

//actions.js
export default {
 action({ state }) {
   setTimeout(() = > {
      console.log(state.name)
  }, 1000);
  },
 anotherAction({ rootState }){
   setTimeout(() = > {
     console.log(rootState.name);
  }, 1000); }};Copy the code

For actions, the mutation is the same

this.$store.dispatch('changeName', {firstName:'han'.lastName:'zhiwei'})
Copy the code

What is a mapActions

The mapActions helper function simply maps the Actions in the store to the component methods

How to use it: Import this helper function first.

import { mapActions} from 'vuex'
Copy the code

Then you can use mapActions in methods

methods:{ ... mapActions({changeName:'changeName'})},Copy the code

This code is equivalent to the following

changeName(payLoad){
  this.$store.dispatch('changeName',payLoad)
}
Copy the code

If the method name is the same as the actions name you can abbreviate it like this

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

Modules modular

What are the modules

When a project is large and has many states, modular management can be adopted. Vuex allows us to split the Store into modules. Each module has its own state, mutation, action, and getter.

Initialize the modules

We learned how to split vuex’s index.js file into a single file for management, so we will still split all modules into a single file for management

Store │ ├ ─ index. Js │ ├ ─ state. The js │ ├ ─ getters. Js │ ├ ─ mutations. Js │ ├ ─ actions. Js │ └ ─ modules │ ├ ─ moduleA// moduleA has the same structure as moduleB│ ├─ ├─ ├.js │ ├─ ├.js │ ├─ ├.js │ ├─ ├.js │ ├─ ├.js │ ├─ ├.js │ ├─ ├.js │ ├─ ├.js │ ├─ ├.jsCopy the code

1. The first root index. In addition to the introduction of its own state in js, getters, mutations, actions, and to introduce two modules of the index, js and export modules in the export


import Vue from 'vue';
import Vuex from 'vuex';
import state from './state';
import getters from './getters';
import mutations from './mutations';
import actions from './actions';
import moduleA  from './modules/moduleA/index';
import moduleB  from './modules/moduleB/index';
Vue.use(Vuex);
export default new Vuex.Store({
  state,
  mutations,
  actions,
  getters,
  modules: {
    moduleA,
    moduleB,
  },
});
Copy the code

2. In moduleA index. Js import moduleA state, getters, mutations, actions. ModuleB similarly

Getters, mutations, and actions are all registered in the global namespace by default, so we can use them in the same way as the root state by default, which makes modularity meaningless, so we need to add namespaced to the module’s index.js: True makes it a module with namespaces. When a module is registered, all its getters, actions, and mutations are automatically named according to the path the module was registered with.


import state from './state';
import getters from './getters';
import mutations from './mutations';
import actions from './actions';
const moduleA = {
  namespaced: true.state: state,
  getters: getters,
  mutations: mutations,
  actions: actions,
};
export default moduleA ;
Copy the code

3. The state under the moduleA, getters, mutations, actions like before learning the export

//state.js
export default {
  name:'hzw'
};
//mutations.js
export default {
 changeName(state, name){ state.name = name; }};// And so on
Copy the code

How is this defined in modularity

state

Write them in their own state.js

getter

In the getter, it takes three parameters, the first is the module state, the second is the module getters, and the third is the root node state rootState

//getters.js
export default {
  nameAndAge(state, getters, rootState) {
    return "Age." + state.age +";"+ getters.realName + "" + rootState.name
  }
};
Copy the code

mutation

The first parameter passed in for mutation is also a state in the module, just as the root state was defined for mutation

export default {
// State is the local state of the module
 changeName(state, name){ state.name = name; }};Copy the code

actions

For action, it will pass in only the context object, where the state property refers to the state in the module and the rootState refers to the rootState, as follows

export default {
 changeName({ state,rootState }) {
        console.log(state.name)
        console.log(rootState .name)
    }
};
Copy the code

How do you develop in modularity

1. The state

This requires a module name in front of the original state name to fetch objects in the module.

this.$store.state.moduleA.name;
Copy the code

The same is true for auxiliary functions, where name is preceded by the module name

. mapState({name: state= > state.moduleA.name, 
})
/ / short. mapState('moduleA'['name']),
Copy the code

Get the state of the root node as before, without adding the module name or root

. mapState(['name']),
Copy the code

2. The getters

This also requires a module name in front of the original state name to fetch objects in the module.

Getters in the root state do not require a module name

store.getters.moduleA.realName
// The first parameter of the map function also needs the module name
computed: {
  // Get getters under moduleA. mapGetters("moduleA"["realName"."nameAndAge"])
  // Get the root getters. mapGetters(["realName"])},Copy the code

Call mutation and action

Based on the calculation of state and getters, mutation and action calls in the module must also add the module name

No module name is required when calling mutation and action in the root state

methods:{
// Call the action under module A. mapActions('moduleA'['changeName'])
// call mutation under module A. mapMutation('moduleB'['changeName'])
// Call the root action. mapActions(['changeName'])
// invoke mutation in root state. mapMutation(['changeName'])}Copy the code

4. It is important to note that {root:true} is passed in as a third argument to action and mutation in the root state of the action and mutation in the module


/ / moduleA actions. Js
export default {
 AsyncChangeName({ commit } ,name) {
   setTimeout(() = > {
     // mutation is called in the root state
     commit('changeName',name,{ root: true });
     // Call the root action
    dispatch('changeName',name,{ root: true });
    }, 1000); }};Copy the code

5. Register the actions in the module as global

When declaring an action, add root:true and place the action definition in the hanler function as follows:

//actions.js
export default {
 globalAction: {root:true.handler({ commit } ,name) {
   setTimeout(() = > {
     commit('changeName',name);
   }, 1000); }}};Copy the code

Now you’re ready to use Vuex for development tasks!

Make an advertisement

This is my open source favorites url project

Project address 👉👉 Click to enter, you can directly set as the browser home page or desktop shortcut for use, I am using, long-term maintenance.

Completely open source, you can research, secondary development. Of course, you are still welcome to click Star⭐⭐⭐ 👉 ⭐ source link (gitee) Source link (github) source link (Github)

Links to integrate

🔊 Project preview address (GitHub Pages):👉👉alanhzw.github. IO

🔊 Project preview alternate address (own server):👉👉warbler.duwanyu.com

🔊 source code address (gitee):👉👉gitee.com/hzw_0174/wa…

🔊 source address (github):👉👉github.com/alanhzw/War…

🔊 My blog :👉👉www.duwanyu.com