What is a vuex

Vuex is a state management tool developed specifically for VUE projects. The so-called state can be simply understood as a variable. Management is storage. Vuex can be understood as a large warehouse for storing our variables.

Why vuex

For example, if I have a state (variable) that is used by many components, then it is no use for me to store this variable to anyone who thinks I am biased. At this point, we need a large repository of variables shared by many components. That’s what vuEX is all about: storing shared state so that all components can use it. Wait, this alone, I think this is also easy to encapsulate, right? I can add a storeObj to the Vue prototype and put these variables in this object:

let storeObj={}; storeObj.a="a"; Vue.prototype.storeObj = storeObj; .Copy the code

Does that work? Of course not, and the important reason is that it doesn’t have a reactive form. The data changes and the page doesn’t respond to its changes. So we don’t use our own sealed warehouse, just use Vuex, it doesn’t smell good.

Which states need to be placed in vuEX

In general, states that need to be shared by multiple components can be placed in VUEX. But not all states are plugged in. Mainly the following several cases

  • User login status, which is used by multiple components and multiple pages.
  • Information in the shopping cart and so on

Using vuex

Step one, download Vuex

Vuex is also a plug-in for Vuejs

npm install vuex --save
Copy the code

Runtime dependencies

Step 2, install the VUex

Create an index.js file that mimics the router. Storing configuration Files

import vuex from "vuex"
import Vue from "vue"
Vue.use(vuex);

Copy the code

If you want to use it in Vue, you must install it using the use method

Step 3: Create the repository

Think about how to create a routing instance, of course there’s a little bit different here it’s not, right

new vuex({})
Copy the code

But by

let store = new vuex.Store({});
export default store;
Copy the code

Third, mount the repository to the root instance

import store from "./store"
new Vue({
	store
    }
})
Copy the code

The core concepts of Vuex

state

This is where the states (variables) are stored. So how does our component use shared state? When the vuex. use method is just called, the vuex.install method is actually called, which binds a $store property to Vue’s prototype object, Prototype. I’m going to assign this created store instance to this property, so how did he get that store instance? Since we have mounted the store instance in the Vue instance, it gets the store instance from options.store: Vue. Prototype.$store= root instance.options. store all components inherit Vue’s prototype, so they all have the $store property.

CPN. $store. State. The variable nameCopy the code

Such as:

const store = new Vuex.Store({ state:{ counter:1 } }); ! [](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7e57a2b95cb0447f9bd1899d778289e8~tplv-k3u1fbpfcp-zoom-1.image)Copy the code

Single state tree

The idea is that instead of creating multiple repositories to store variables by category, create one repository to store state, because creating multiple repositories is not easy to manage and maintain

mutation

Mutation is used to modify state. And the only way to change state is to commit mutationMutation defines a series of methods that modify state and pass in a state object as the default first argument. ** lest we use this. Such as: So how do we use mutation?

CPN. $store. Mutations. The add () / / wrongCopy the code

Like this? No, it’s not, it’s in the form of.commit

Cpn.codestore.com MIT ("add")// Add is a custom methodCopy the code

For example, here I use it in app.vue: As you can see, the state in state was mutated, and devtool recorded its modification for us.

Methods in mutation carry parameters

The first parameter of a mutation method must be a state attribute passed into the repository. What if I want to pass the parameter when I call a mutation method? For example, the add in mutations can only be added by one, so how can I make it add any number, which I want to decide by myself. Simple: We set a parameter to receive the parameter in two steps:

  • When defining a method, set a parameter with a hole, such as num here:

  • When you submit a method, you pass in parameters, something like this
cpn.$store.commit("add",5); // 5 will be assigned to numCopy the code

Here we can implement the previous requirement: index.js: app.vue: Effect:

Mutation submission style

There are two forms of mutation submission.

  • this.$store.commit("add",num); That’s the form we used before
  • In the second form, commit passes in an object: the type attribute, which puts the method name. So let’s say I switch from the previous form
	this.$store.commit({
    	type:"add",
        num:num
    })
Copy the code

The special thing to note about the second form is that the second parameter in the mumation method should be this object

Mutations :{add(state,num){// in this form, the num should be the object. state.counter=state.counter+num; }Copy the code

Num =={type:”add”,num:num}, if you want to use the num we just passed in,num

mutations:{
    add(state,num){
      state.counter=state.counter+num.num;
    }
Copy the code

Matation type constant

Its purpose is to unify the names of the methods in mutation. Even though you might call it AAA, you should call it AAA when you use it. If we accidentally type something wrong, such as aAAA, then the commit will not take effect. So this is all about consistency between declaration and use of method names. The first thing to know is:

var obj = {
  ["a"]:function(){
  }
}
var obj = {
a:function(){
}
}
Copy the code

The two methods are actually the same, so we can mutate the method in mutation.

Mutations :{add(state,num){state.counter=state.counter+num; Mutations :{["add"](state,num){state.counter=state.counter+num; }}Copy the code

So we can do this by creating a file: mutation-types.js

//mutation-types.js export const Add = "Add "; Mutations :{[Add](state,num){return mutations:{return mutations:{return mutations:{return mutations:{return mutations:{return mutations:{return mutations:{ state.counter=state.counter+num; } // Import export {Add} from".... in the component where you want to submit this method /mutation-types.js" this.$store.commit(Add,num);Copy the code

Notice that this is all pseudo-code. Just a brief description of how to use it.

How to change state

The state can only be modified using mutationThis is the official picture. It doesn’t have a line where Vue Components point to State. Why can’t we do that? Changes can be made, but Devtools is an official browser plugin that tracks state changes in Vuex. Is not able to listen for changes made by this route. It can only listen for mutation changes in the vuEX state. (Devtools is an official browser plugin that tracks state changes in Vuex.)

getters

What is the getters

Actually getters and computed properties in our example, computed. It’s pretty much the same thing.

When to use Getters

When we want to use a variation of a variable in state, we can use getters. Pretty much the same as our calculated properties.

How do I use Getters

  • When creating the repository, define getTers. Such as:

  • Use getters in any component, for example:

Tips for using getters

  1. Getters is a property, not a function

One thing to note here is that while the getters property is defined to look like a method, it is essentially a property!! It’s not a function, because I guess it’s consistent with the calculated property being a propertyIf you use it as a function, you will get an error. Look!2. The get function of getters actually has two parameters, but the second parameter is optional. The first parameter is to pass in the state attribute of the warehouse, and the second parameter is to pass in the getters attribute.

Getters :{sqrtCounter(state){// This function can actually take two arguments. The second argument is optional. The first argument is to pass in the state property of the warehouse. The second argument is to pass the warehouse's getters property to return state.counter*state.counter; }}Copy the code
  1. Getters itself is a property, so you can’t pass parameters. If you want to pass parameters, you should return a function to the calculated property.
getters:{ addNum(state){ return function (a){ return state.counter+a; }}}Copy the code

actions

As we said before, the operation of modifying the state in state can only be put into mutations, but mutations can only have synchronous operation, not asynchronous operation. We need to separate the asynchronous operation and divide it into actions. In other words, actions are all asynchronous. So why can’t there be asynchronous operations on mutations? Devtool is listening for mutations. Mutations cannot listen for state changes if there is an asynchronous operation. So we need to separate out the asynchronous operations. For example, I will change the code of the previous mutations :(add a timer)

Mutations :{add(state,num){setTimeout(()=>state.counter=state.counter+ 100)}}Copy the code

Obviously this timer is asynchronous code, so we need to separate it out:

actions:{
	addNum(){
    	   setTimeout(()=>state.counter=state.counter+num,100)
	}
}

Copy the code

Is this separation? No, be sure to remember that mutations are necessary to change the state in state. Therefore, the synchronization code for modifying the status should still be included in mutations. So I’m going to separate out the modified code

addNumber(state){ state.counter=state.counter+1 } }, actions:{ addNum(){ setTimeout(()=>??? , 100).}}Copy the code

** Next we will encounter a new problem, how can we use the method defined in mutations in the actions? ** Every method defined in actions takes a parameter and receives the created Store object. The store object is of course called by commit. So it would look something like this:

mutations:{
	addNumber(state){
   	 state.counter=state.counter+1
    }
},
actions:{
	addNum(context){
    	   setTimeout(()=>context.commit("addNumber"),100)
	}
}
Copy the code

Now we have a new problem how do we call actions in the component?

** In the component, we invoke methods in actions using Dispatch. ** So the code should be modified

/ / store/index. In js/ / in the app. In vueEffect:You can see that we’ve made it,And devTools allows you to listen for this change

Pass arguments when calling methods in Actions

Methods in actions. The first parameter is a store object by default. We can set another parameter to receive

Actions :{addNum(context,num){//num receives setTimeout(()=>context.com MIT ("addNumber"),100)}}Copy the code

When I call a method in actions I just pass it in

this.$store.dispatch("addNumber",123); / / 123 to the numCopy the code

modules

Since vuex’s principle is a single state tree, it creates a store store where all data is stored. This will result in a variety of states stored in the Store repository, and sometimes we need to separate them into categories. This is where our Modules come into play. It looks like this:

const store = new Vuex.Store({ modules:{ a:{ state:{num:1}, actions:{}, mutations:{} getters:{} }, b:{ state:{}, actions:{}, mutations:{} getters:{} }... }}}Copy the code

Is each module corresponds to an object, the object has its own state, actions, mutations, getters. Points needing attention include:

  • Actions,mutations, and getters in the module all serve the state in the module. For example,mutations will pass in state the first parameter of the method, so the state passed in should be the state in the module.
  • Used in the component module of the actions/getters/mutations, and before the same, no difference. But the use of state is a bit strange. It should be this.$store. Module name. variable names such as here

num:this.$store.a.num

  • The method in mutations in the module The first parameter passes state in the module
  • The first argument to get is the state of the module, the second argument is the getters of the module, and the third argument is the state of the root.
  • The actions parameter in a module is passed the corresponding object of the module. That’s the value of our property a over b. It also has a property rootState, which gets the state of the root object. Let’s say the parameter is context.

So, context.state corresponds to the module’s state context.actions corresponds to the module’s actions Context. getters corresponds to the module’s getters context. Mutations corresponds to the module’s mutations, Context. rootState State of the root object.

Structure of the organization

As the project of large, may be the last index. Js appear unusually large, so we can put the getters/mutations/actions/code modules are pulled out, the formation of such file directory structure.

The responsive principle of State in VUEX

As mentioned earlier, variables in the VUEX repository and data in data are reactive, which means that the data has changed. The page immediately refreshes in response to this change.

 let store = new vuex.Store({
 state:{
 counter:1,
 obj:{
 num:1,
 str:"a"
 }
 }
 })
Copy the code

Here I have two values in my state, one for the underlying data type and one for the reference type. They will all be added to vUE’s responsive system. All attributes of the reference type are added to the reactive system.That is, obj.num/obj.str/counter are both reactive.They’re all added to a responsive system.

But if I add a property to OBj, I’m not actually adding a responsive property. It’s when the data changes, but it’s not updated to the page.

Here’s an example:There’s an OBJ object in state, and I’m going to define a method change on mutations which is the changeObj method here. Then IN app.vue:First, show obJ in state. Then click the button to change it. Find that the page is not updated, but the OBJ in state does change, which is not responsive.

How do I add a property to be responsive

The set method in Vue is required.

Vue.set(object to be added, property name (object is string and array is number), property value);Copy the code

So the above example can be implemented like this:

 changeObj(state){
      Vue.set(state.obj,"c","3");
    }
Copy the code

How do I delete a property to be responsive

Delete obj. Attribute nameCopy the code

The usual way to do this is but instead of being reactive, you still have to use Vue’s delete method.

Vue.delete(obj/arr,string/number);
Copy the code