What the hell is vuex?
install
I won’t talk about the specific installation of vuex here. The official information is relatively clear,Poke here to enter。 However, two points should be noted:
- In a modular packaging system, you must explicitly use the
Vue.use()
To install vuex, for example:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use (vuex) // this function must be called to inject vuex
- When using the global script tag to refer to vuex, you don’t have to worry about it. Just refer to it directly, but you should pay attention to the sequence of references, as follows:
//After Vue, the introduction of vuex will automatically install
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>
Although script seems to be more automatic, you will understand that modularity is actually our best posture after more contact.
Unveiling vuex
When we get a tool, what we need to understand at the first time is what problems it can help us solve. For example, hammers, broken eggs, hit the phone, such as apples, can not only eat but also play. What about vuex, if you put Vue.js If he wants to go next door to buy a pack of cigarettes, he can just walk there. Driving a car is a burden. But if he wants to go tens of kilometers to school to pick flowers, then Santana will have to be used. Otherwise, when he goes there, all the flowers may wither.
Of course, the analogy is just to tell us the value of vuex. In practical application,What can it do? When do you need to turn its cards?
Let’s take a look at the official Code:
new Vue({
//State data source
data () {
return {
count: 0
}
},
//View view
template: `
<div>{{ count }}</div>
`,
//Actions event
methods: {
increment () {
this.count++
}
}
})
This is a very simple growth counting function page, andVue.jsIf you have a leg, you should understand. By eventincrement
, implementationcount
Grow, and then render to the interface.
In fact, this way is just like walking to buy cigarettes. It is a short-distance effect. It is easy to understand that the government calls it “one-way data flow”.
Unidirectional data flow
However, the situation has changed. Now there are two pages a and B, and the following two requirements:
- They are required to be able to
count
Control. - Request a has been revised
count
B should know immediately after B changes, and a should know immediately after B changes.
What should I do? A little bit of development experience, you can easily think of, the data sourcecount
Split it off and manage it in a global variable or global singleton mode, so that it is not easy to get this state on any page.
Yeah, that’s the idea behind vuex. That’s what it does. Is there a feeling that vuex, a big name, is harming you? It’s the global model. It’s also possible to do without it.
Yes, it can be done, just like you can go to school to see flowers without Santana, but the process is different.
The purpose of vuex is to manage the shared state. In order to achieve this goal, it makes a series of rules, such as modifying the data source state, triggering actions and so on. All of them need to follow its rules, so as to make the project structure clearer and easier to maintain.
Let’s look at the official description
Vuex is a Vue.js State management mode of application development. It uses centralized storage to manage the state of all components of the application, and ensures that the state changes in a predictable way with corresponding rules.
There is no instant clearer.
When do you turn vuex
In fact, after understanding what vuex is going to do, it’s much easier to choose when to turn over the cards. Just like the previous analogy, when you go to the next room to buy a pack of cigarettes and open a Santana, when you look for a parking space, you smoke out.
Therefore, we need to measure the short-term and long-term benefits according to the needs of the project. If we don’t plan to develop large single page applications, vuex may still be a burden for you. For some small and medium-sized projects, if you are lazy to walk and feel troublesome to drive, you can ride a bike.
The bike sharing here refers to a simple official bike sharingStore modeIs actually a simple global object.
The difference between global objects and vuex is relatively easy to understand
Vuex differs from simple global objects in the following two aspects:
- Vuex’s state storage is responsive. When Vue components read the state from the store, if the state in the store changes, the corresponding components will be updated efficiently.
- You can’t directly change the state in the store. The only way to change the state in a store is to explicitlyCommit mutation。 This makes it easy for us to track every state change, so that we can implement some tools to help us better understand our application.
Simple example
//If you are in a modular build system, make sure you call it at the beginning Vue.use (Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
The core of every vuex application is the store. A store is basically a container that contains most of the information in your applicationState。
Note: if mutations don’t know what it is, it doesn’t matter. It will be explained later. It can be simply understood that it can only modify the data in the state by using the methods in it.
store.commit ('increment ') // call methods in mutations
console.log(store.state.count) // -> 1
The government also gave specific reasons for the design
We submit the mutations instead of changing them directly store.state.count Because we want to track state changes more clearly. This simple convention can make your intention more obvious, so that when you read the code, you can more easily understand the state changes inside the application. In addition, this also gives us the opportunity to implement some debugging tools that can record every state change and save the state snapshot. With it, we can even achieve a debugging experience like time travel.
Because the state in store is responsive, the state in calling store in components is simple, and only needs to be returned in the computed property. Triggering a change is only to submit a mutation in the methods of the component.
Vuex’s state and getter
Similarly, we have learned that vuex, like a global administrator, helps us to manage the shared data of projects in a unified way. What kind of way is it managed? How can we communicate with the administrator in order to access and operate the shared data effectively?
One more word
The viscera of vuex consists of five parts: state, getter, mutation, action and module. As for these five parts, I will divide them into several chapters to elaborate in detail. In this lecture, I will work with you to thoroughly deal with state and getter.
Of course, in practical application, these five parts are not necessary. You can add whatever you need. But generally, no matter how simple vuex is, it will at least consist of state and mutation. Otherwise, you should consider whether vuex is necessary.
Finally, warm tips, the document sample code uses the syntax of es2015, if you have not yet understood, firstKnow more about this。
Single state tree
Vuex usesSingle state treeAccording to the official description, it may be a little confused, but it doesn’t matter. Here we’ll learn more about what isSingle state tree。 Let’s take a look at the meaning of trees. “
organizational structure
As shown in the figure above, the organizational structure of a company belongs to a tree structure. The general manager is the trunk of the tree, and other departments or occupations belong to the branches of the tree.
Generally speaking, a company will only have such a tree structure. If there are two equal general managers, there may be conflicts in the management of the company. Who will listen to the people below, right!
OK, now let’s take a look at the official narrativeSingle state tree:
1. Use an object
(trunk)
That’s all(Branch)
Application level status. “
2. Per app(company)
Only one store instance object will be included(trunk)
。Single state tree allows us to locate any specific state fragment directly, and can easily get a snapshot of the current application state during debugging.
State
Let’s go back to the simple store sample code:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
}
})
So how do we present state in Vue components? Because the state storage of vuex is responsive, the easiest way to read the state from the store instance is in theCalculation propertiesReturns a status as follows:
//Create a counter component
const Counter = {
data() { return {} },
template: `<div>{{ count }}</div>`,
computed: {
count () {
return store.state.count
}
}
}
whenever
store.state.count
When it changes, it will retrieve the calculated properties and refresh the interface.
It’s important to note that if youstore.state.count
In data,store.state.count
The change of the interface will not trigger the refresh of the interface. Of course, it cannot be done directly<div>{{ store.state.count }}</div>
Because you can’t directly access the store object in the template, you will undoubtedly report an error if you write in this way.
This mode depends on the global administrator store. If there are too many modules, it means that every module or page needs to introduce the store as long as it uses the data in this state. This kind of operation is really a bit uncomfortable. Of course, the government certainly does not allow such a crazy operation:
Through the store option, vuex provides a mechanism to “inject” the state from the root component into each sub component (to be called) Vue.use (Vuex)):
const app = new Vue({
el: '#app',
//Provide the store object to the "store" option,
//This can inject an instance of the store into all the subcomponents
store,
//Subcomponents
components: { Counter },
template: `
<div class="app">
<counter></counter>
</div>
`
})
By registering the store option in the root instance, the store instance will be injected into all the subcomponents under the root component, and the subcomponents can be accessed through this. $store. Let’s update the implementation of counter
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}
Vuex is easy to use, but don’t abuse it
Using vuex doesn’t mean you need to put all the states in vuex. Although putting all the states into vuex makes the state changes more explicit and easier to debug, it also makes the code lengthy and non intuitive. If some states strictly belong to a single component, it’s better to be a local state of the component. You should make trade-offs and decisions based on your application development needs.
Getter
Sometimes, we will find that the data in the state is not what we want directly, but needs to be processed to meet our needs.
For example, in a component, we need to change the date in the statedate
Convert to the day of the week to show:
computed: {
weekDate () {
return moment(this.$store.state.date).format('dddd');
}
}
Note: Here’s themomentIs a third-party date processing class library, need to import before using.
If only one component needs to do this, it’s OK, but if many components need to do this transformation, then you need to copy this function in each component. What’s more, once the product manager is in a bad mood and doesn’t want to use the day of the week to show it, he wants to use it directly2018-10-30 11:12:23
If you want to display the date in this way, you have to change the date formatting method in all the components that use it. Even if you extract it separately as a public function, all kinds of import is also troublesome. The most important thing is that it is not well managed.
So, at this time, vuex introduced another awesome thing,Getter。 We can think of it as a computed property in the store.
Just like calculating a property, the return value of a getter is cached according to its dependency, and is recalculated only when its dependency value changes.
Let’s take a look at these two examples and focus on the following notes:
const store = new Vuex.Store({
state: {
date: new Date()
},
getters: {
//Getter takes state as its first parameter
weekDate: state => {
return moment(state.date).format('dddd');
}
}
})
getters: {
//Getter can also receive getters as a second parameter
dateLength: (state, getters) => {
return getters.weekDate.length;
}
}
Not only that, getter will store.getters Objects are exposed, and you can access these values in the form of attributes:
console.log(store.getters.weekDate)
We can easily use it in any component:
computed: {
weekDate () {
return this.$store.getters.weekDate
}
}
Now the demand has changed again. The format of weekdate to be displayed in each module is different. Some need to display all the dates, and some need to display the day of the week. What should I do?
It’s easy to do, so you can send it to getter, but how?
Since getter is cached as part of Vue’s responsive system when accessed through attributes, it cannot be accessed directlystore.getters.weekDate('MM Do YY')
Because weekdate is not a function, it’s just a property.
Now that the attribute can’t pass parameters, what should I do? Let’s try to turn this property into a function.
getters: {
//Return a function, you can pass parameters
weekDate: (state) => (fm) => {
return moment(state.date).format(fm ? fm : 'dddd');
}
}
The usage is as follows:
store.getters.weekDate('MM Do YY')
Maybe children’s shoes who have read the official documents will wonder why they didn’t explain those auxiliary functions, such asmapState
、mapGetters
。 Don’t worry, there will be a special chapter to explain it later, because I found that these auxiliary functions (including the followingmapMutations
andmapActions
)They are all created to solve the same problem, only in different forms, so it’s better to talk about it together, maybe the effect will be better.
Vuex’s station
Last lectureVuex’s state and getter, which tells us how to use the state data in the warehouse. Of course, it’s not enough to use it alone. Most application scenarios still have to control these states. How to control them is the key point of this lecture.
Only mutation state
The only way to change the state in vuex’s store is to submit a mutation.Mutations in vuex are very similar to events: each mutation has a string event type and a callback function. This callback function is where we actually change the state, and it will accept state as the first parameter
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
//The event type is increment
increment (state) {
//Change status
state.count++
}
}
})
Note that we can’t directlystore.mutations.increment()
Vuex specifies that thestore.commit
To trigger the corresponding type:
store.commit('increment')
Chuanshen
We can also ask store.commit Pass in additional parameters:
mutations: {
increment (state, n) {
state.count += n
}
}
//Call
store.commit('increment', 10)
For this extra parameter in the mutation, the official gave it the name of “tall”Load (payload)。 To be honest, I saw this title in the document for the first time“Submit load”I really don’t want to look down.
We are often not defeated by these unsophisticated concepts, but by our own inner fear.
In most cases, the load is an object that makes it easier to read:
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
There are two ways to submit:
//1. Submit load and type separately
store.commit('increment', {
amount: 10
})
//2. The whole object is transferred to the mutation function as a load
store.commit({
type: 'increment',
amount: 10
})
Of course, there is no absolute limit to which way to use. It depends on my own preferences. As far as I am concerned, I prefer to use the second posture, which is more realistic together.
Modify the rules
It’s easy to modify the state data of the basic type. There are no restrictions, but if you modify the object, you should pay attention to it. For example:
const store = new Vuex.Store({
state: {
student: {
Name: 'Xiao Ming',
Sex: 'female'
}
}
})
At this time, if we want to givestudent
Add an ageage: 18
What should we do?
Yes, directlysex
Now, just add this field. It’s best to do this. But what if we want to change it dynamically? Then you have to follow Vue’s rules. As follows:
mutations: {
addAge (state) {
Vue.set(state.student, 'age', 18)
//Or:
// state.student = { ...state.student, age: 18 }
}
}
The above are two ways to add attributes to an object. Of course, if you want to modify the specific value of an added object, you can change it directly, such asstate.student.age=20
That’s it.
As for why, we have learned before, because the state in the store is responsive. When we change the state data, the Vue component that monitors the state will also be updated automatically. Therefore, the mutation in vuex also needs to follow these rules as well as using Vue.
Use constants
This is to replace the name of the mutation event with a constant.
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'
const store = new Vuex.Store({
state: { ... },
mutations: {
//Use the es2015 style computational property naming function to use a constant as the function name
[SOME_MUTATION] (state) {
// mutate state
}
}
})
Some people may have doubts. What’s the use of doing this? You have to create more type files and import them when you use them. Isn’t it troublesome!
Let’s see how the mutation is calledstore.commit('increment')
You can find that here is the method of commit submissionincrement
In the form of a string. If the project is small and developed by one person, it’s OK. However, if the project is large and there are more people writing code, it’s troublesome. Because there are many ways to commit, it will be particularly confusing. Moreover, if it is substituted in the form of string, it’s very difficult to check if something goes wrong.
Therefore, for large projects with multi person cooperation, it’s better to use the constant form to deal with the mutation. For small projects, it doesn’t matter, just want to be lazy.
Must be a synchronous function
It’s important to remember,Mutation must be a synchronous function.Why?
As mentioned earlier, the reason why we want to change the state data by submitting a mutation is that we want to track the change of state more clearly. If it is asynchronous as follows:
mutations: {
someMutation (state) {
api.callAsyncMethod(() => {
state.count++
})
}
}
We don’t know when the state will change, so we can’t track it. This is contrary to the original design of the station, so it is mandatory that it must be a synchronous function.
store.commit('increment')
//Any state changes caused by "increment" should be completed at this point.
Action under vuex
Through the previous lectureVuex’s station, we know how to modify the data of a state, and we can only submit the modification through the mutation. In addition, we also know that the mutation must be a synchronous function. What if the asynchronous function must be used in the requirement?
Easy to do, then it’s action’s turn.
Brief introduction
Action is similar to mutation, except that:
1. Action submits a mutation, not a direct change of state. “
2. An action can contain any asynchronous operation.
Let’s look at a simple example of action
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
As you can see, the action function takes acontext
Parameter. Note that this parameter is not general. It has the same methods and properties as the store instance, but they are not the same instance. I will explain why they are different when I learn modules later.
So you can use it herecontext.commit
To submit a mutation, or throughcontext.state
andcontext.getters
To get the state and getters.
Of course, to simplify the code, we can use theParametric deconstructionIt’s easy to expandcommit
、state
And so on. As follows:
actions: {
increment ({ commit }) {
commit('increment')
}
}
Distribute action
store.dispatch('increment')
Station passed
store.commit
Trigger, then actionstore.dispatch
Method trigger.At first glance, it seems unnecessary. Isn’t it more convenient for us to distribute the mutation directly? In fact, this is not the case. Remember that mutation must execute this restriction synchronously? Action is not bound! We can perform asynchronous operations inside the action
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
It’s the same as the way of distribution of musicdispatch
:
//Distributed as load
store.dispatch('incrementAsync', {
amount: 10
})
//Distribute as objects
store.dispatch({
type: 'incrementAsync',
amount: 10
})
Let’s take a more practical shopping cart example, which involves calling asynchronous API and distributing multiple mutations
actions: {
checkout ({ commit, state }, products) {
//Back up the items in the current shopping cart
const savedCartItems = [...state.cart.added]
//Make a checkout request and then empty the cart optimistically
commit(types.CHECKOUT_REQUEST)
//The shopping API accepts a success callback and a failure callback
shop.buyProducts(
products,
//Successful operation
() => commit(types.CHECKOUT_SUCCESS),
//Failed operation
() => commit(types.CHECKOUT_FAILURE, savedCartItems)
)
}
}
Note that a series of asynchronous operations are in progress in the example, and the side effects of the action (i.e. state changes) are recorded by submitting a mutation.
Combined action
Action is usually asynchronous, so how do you know when an action ends? More importantly, how can we combine multiple actions to handle more complex asynchronous processes?
First, you need to understand
store.dispatch
Can handle the promise returned by the handler of the triggered action, andstore.dispatch
Still return promise:
I don’t know what promise isLet’s get to know。
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}
Call:
store.dispatch('actionA').then(() => {
// ...
})
Of course, it can also be like this:
actions: {
// ...
actionB ({ dispatch, commit }) {
return dispatch('actionA').then(() => {
commit('someOtherMutation')
})
}
}
We can also use itasync / awaitHow to combine actions:
//Suppose getdata() and getotherdata() return promise
actions: {
async actionA ({ commit }) {
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
Await dispatch ('actiona ') // wait for actiona to complete
commit('gotOtherData', await getOtherData())
}
}
One
store.dispatch
Multiple action functions can be triggered in different modules. In this case, the return promise is executed only after all trigger functions have completed.
We often encounter this kind of situation in actual projects. For example, you want to handle B event now, but B event needs a kind of resource, and this kind of resource must be obtained through a event. At this time, we need to combine actions to handle these events.
Vuex’s little helper
I’ve talked about the four carriages of state, getter, mutation and action under vuex. I don’t know if you have understood them. Of course, if you want to really master it, you still need constant practice and hands-on practice.
In fact, as long as you master the four carriages, you will have no problem in dealing with some small and medium-sized projects. The ultimate carriage of module is actually to deal with those slightly large and complex projects and avoid store There are too many data in it, so it’s difficult to manage and design. This cart is a little more abstract and not easy to control. Let’s explain it in detail next time.
Many of the supporting facilities in Vue have been pursuing simplicity and perfection in the use experience, so this is a very important reason why Vue has won the hearts of the people for a long time. In this lecture, let’s talk about some common auxiliary functions of vuex.
mapState
Through the previous learning, we know that the easiest way to read the state from the store instance is toCalculation propertiesReturns a state in the.
So, what happens when a component needs to get multiple states? Is that right
export default {
...
computed: {
a () {
return store.state.a
},
b () {
return store.state.b
},
c () {
return store.state.c
},
...
}
}
Of course, this is no problem, but always feel very uncomfortable to write, it looks even more uncomfortable, right! Since it’s so easy for us to feel it, can vuex not feel it, can we bear it?
Absolutely not, somapState
Auxiliary functions have been created to deal with the pain points of this person’s gnashing teeth.
//In the separately built version, the auxiliary function is Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
//Arrow functions make the code more concise
a: state => state.a,
b: state => state.b,
c: state => state.c,
//Pass string parameter 'B'
//Equivalent to ` state = > state. B`
bAlias: 'b',
//To be able to use 'this' to get the local state
//Regular functions must be used
cInfo (state) {
return state.c + this.info
}
})
}
From the above example, we can see that we can directly store all the needed states in themapState
There is a unified management, but also can take alias, do additional operations and so on.
If the name of the mapped calculation attribute is the same as the name of the child node of the state, we can simplify it and give themapState
Pass a string array:
computed: mapState([
//Map this. A to store.state .a
'a',
'b',
'c'
])
becausecomputed
This calculation property receives an object, so you can see from the example code above,mapState
The function returns an object. If you want to mix it with local calculation properties, you can use ES6 syntax to simplify it
computed: {
localComputed () {
...
},
//Use the object expansion operator to blend this object into an external object
...mapState({
// ...
})
}
I seemapState
After the auxiliary function, the usage of the following auxiliary functions is almost the same. Let’s go on.
mapGetters
This andmapState
Basically, there is no difference. Just look at the official examples
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
To get an alias, use the form of an object. The following example means tothis.doneCount
Map tothis.$store.getters.doneTodosCount
。
mapGetters({
doneCount: 'doneTodosCount'
})
mapMutations
Look directly at the sample code:
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
//Will` this.increment () 'mapped to
// `this.$store.commit('increment')`
'increment',
//'mapmutations' also supports loads:
//Will` this.incrementBy (amount) ` map to
// `this.$store.commit('incrementBy', amount)`
'incrementBy'
]),
...mapMutations({
//Will` this.add () 'mapped to
// `this.$store.commit('increment')`
add: 'increment'
})
}
}
It’s not easy to use. Serial loads can be directly supported.
mapActions
andmapMutations
As like as two peas, change your name.
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
//Will` this.increment () 'mapped to
// `this.$store. dispatch('increment')`
'increment',
//Mapactions also supports payload:
//Will` this.incrementBy (amount) ` map to
// `this.$store. dispatch('incrementBy', amount)`
'incrementBy'
]),
...mapActions({
//Will` this.add () 'mapped to
// `this.$store. dispatch('increment')`
add: 'increment'
})
}
}
Want to invoke in component, directlythis.xxx
It’s over.
Vuex administrator module
This is the last and most complex lecture of vuex foundation. It may be a bit difficult for beginners to accept if they come according to the official rules, so after thinking about it, I decided to spend more time to explain it with a simple example, and review the previous knowledge by the way.
First of all, we need to understand the background of module. We know that vuex uses a single state tree, and all the states of the application are centralized into one object. If the project is relatively large, the corresponding state data will certainly be more. In this way, the store object will become very bloated and difficult to manage.
It’s like a company is run by the boss alone. If the small company is OK, if the company is a little bigger, it will be in trouble. At this time, the boss will set up major departments and arrange a supervisor for each department to assign the management tasks. If there is anything to deal with, he only needs to communicate with these supervisors, and then the supervisor will assign the tasks. This will greatly improve the work efficiency and reduce the burden of the boss.
In the same way, the module actually assumes the role of department administrator, and the store is the boss. After understanding this level, it will be much easier to do. Next, let’s start to practice step by step.
1、 Preparation
Here we use the officialvue-cliTo build a project called “vuex test.”. Of course, you have to install Vue cli first:
npm install -g @vue/cli
# OR
yarn global add @vue/cli
After the installation is complete, you can use the following command to create the project:
vue create vuex-test
You can also use a graphical interface to create:
vue ui
The specific usage of Vue cli can be viewed officially,Poke here to enter 。
After the project is created, find the directory where the project is installed, and open the console to execute:
//First navigate to the project directory
cd vuex-test
//Then install vuex
npm install vuex --save
//Run it
npm run serve
After running, it can be openedhttp://localhost:8080/Let’s see the effect.
Finally, we find a favorite ide to open this project, which is convenient for viewing and editing. I personally prefer to use webstore, and I recommend it here.
2、 Simple start
Default structure diagram for the project
Here, we just looksrc
Directory, the rest of the time. assemblycomponents
It’s not within the scope of this, so we can also ignore resourcesassets
There’s nothing to say. If there are pictures or videos, just put them in this folder.
We open itApp.vue
File, remove the component related code, and write a little simple Vue code. It is amended as follows:
<template>
<div id="app">
<img src="./assets/logo.png" />
<h1>{{name}}</h1>
< button @ Click = "modifynameaction" > Modify name < / button >
</div>
</template>
<script>
export default {
data() {
return {
name: 'Lucy'
}
},
methods: {
modifyNameAction() {
this.name = "bighone"
}
}
}
</script>
Now let’s introduce vuex and use it to manage state data, such as herename
。 First of allsrc
Create a new one instore.js
File, and write the following familiar Code:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
name: 'Lucy',
},
mutations: {
setName(state, newName) {
state.name = newName;
}
},
actions: {
modifyName({commit}, newName) {
commit('setName', newName);
}
}
});
Then, in themain.js
Import fromstore
And global injection:
import store from './store';
// ...
new Vue({
store,
render: h => h(App),
}).$mount('#app')
Final revisionApp.vue
The code in is as follows:
<script>
import {mapState, mapActions} from 'vuex';
export default {
computed: {
...mapState(['name'])
},
methods: {
...mapActions(['modifyName']),
modifyNameAction() {
this.modifyName('bighone');
}
},
}
</script>
I think it’s no problem to understand these codes, because these are very basic knowledge points of vuex. Here’s a brief review of the practical operation to deepen the impression. If you don’t understand, it proves that you haven’t mastered the basic knowledge before.
3、 Introduction of module
In the foreword, we have explained the basic responsibilities of the module, so how to use it?
Vuex allows us to divide the store into large and small objects. Each object also has its own state, getter, mutation and action. This object is called a module, in which sub modules and sub modules can be embedded
Now insrc
There’s a folder inside, namedmodule
And then create a new one insidemoduleA.js
File, and write the following code:
export default {
state: {
text: 'moduleA'
},
getters: {},
mutations: {},
actions: {}
}
As above, build another onemoduleB.js
The document is not repeated here.
Then open itstore.js
File, import the two modules:
import moduleA from './module/moduleA';
import moduleB from './module/moduleB';
export default new Vuex.Store({
modules: {
moduleA, moduleB,
},
// ...
}
At this time, two sub modules have been injected into the storemoduleA moduleB
, we canApp.vue
Passed inthis.$store.state.moduleA.text
This way to directly access the state data in the module. As follows:
// ...
computed: {
...mapState({
name: state => state.moduleA.text
}),
},
// ...
Therefore, the internal state of the module is local and only belongs to the module itself, so the external state must be accessed through the corresponding module name.
howeverNote:
Action, mutation and getter in the module can be registered in theGlobal Namespace This enables multiple modules to respond to the same mutation or action.
Here, take the response of mutation as an example, add a mutation to ModuleA and a mutation to moduleb, as follows:
mutations: {
setText(state) {
state.text = 'A'
}
},
Module B is the same as above. Just change the name of the text. There will be no repetition here. And then backApp.vue
In the text, it is amended as follows:
<script>
import {mapState, mapMutations} from 'vuex';
export default {
computed: {
...mapState({
name: state => ( state.moduleA.text +'and'+ state.moduleB.text )
}),
},
methods: {
...mapMutations(['setText']),
modifyNameAction() {
this.setText();
}
},
}
</script>
Run it and click Modify, and we will find thetext
The values have changed. Of course, as like as two peas of action, you can try it.
If there is an intersection of data between modules, we can update the data between modules synchronously in this way. Although it seems very convenient, we must be careful when using it. Once this method is not used well and errors are encountered, it is difficult to check.
4、 Access the root node
We already know that the internal state of the module is local and belongs only to the module itself. So what if we want to access the data state of the store root node in the module?
It’s very simple. We can get it through the parameter rootstate in the getter and action inside the module. Next, let’s give it to youmodelA.js
Add a bit of code to the file.
export default {
// ...
getters: {
//Note: rootstate must be the third parameter
detail(state, getters, rootState) {
return state.text + '-' + rootState.name;
}
},
actions: {
callAction({state, rootState}) {
alert(state.text + '-' + rootState.name);
}
}
}
Then modify itApp.vue
:
<script>
import {mapActions, mapGetters} from 'vuex';
export default {
computed: {
...mapGetters({
name: 'detail'
}),
},
methods: {
...mapActions(['callAction']),
modifyNameAction() {
this.callAction();
}
},
}
</script>
Then run it and you will find that the data of the root node has been obtained by us. It should be noted that in getters, rootstate is exposed by the third parameter. In addition, there is a fourth parameter, rootgetters, which is used to obtain the getters information of the root node. I won’t show it here. If you are interested, you can try it. The only thing to emphasize is that you must not mistake the position of parameters.
Of course, rootgetters can also be received in action, but in action, because all the data it receives is wrapped in thecontext
Object, so there is no restriction on the order of unpacking.
5、 Namespace
As we already know, action, mutation and getter in the module are registered in the global namespace by default. What if we just want them to work in the current module?
By addingnamespaced: true
Make it a module with a namespace.When a module is registered, all its getters, actions and mutations will automatically be named according to the registered path of the module.
We are heremoduleA.js
Add innamespaced: true
。
export default {
namespaced: true,
// ...
}
If you run the code at this time, you will find the following error:
[vuex] unknown getter: detail
Not found in global getterdetail
Because its road strength has changed, it no longer belongs to the global, only belongs to module a. So, at this time, if we want to visit it, we must take the road. modifyApp.vue
As follows:
<script>
import {mapActions, mapGetters} from 'vuex';
export default {
computed: {
...mapGetters({
name: 'moduleA/detail'
}),
},
methods: {
...mapActions({
call: 'moduleA/callAction'
}),
modifyNameAction() {
this.call();
}
},
}
</script>
The first mock exam is that if a module is enabled, the getter, dispatch and commit in getter and action are localized, and there is no need to add space name prefix in the same module. That is to say, changenamespaced
Property does not need to modify any code in the module.
So what do we doAccessing global content within a module with a namespaceWhat about it?
Through the previous study, we have learned that:
If you want to use global state and getter, rootstate and rootgetter will be passed into getter as the third and fourth parameters, and action will also be passed in through the properties of context object.
Now if you want to distribute an action or submit a mutation in the global namespace, we just need to{ root: true }
As the third parameter, it can be passed to dispatch or commit.
export default {
namespaced: true,
// ...
actions: {
callAction({state, commit, rootState}) {
Commit ('setname ','change', {root: true});
alert(state.text + '-' + rootState.name);
}
}
}
Now let’s see howRegister global action in module with namespace。
If you need to register global actions in a module with a namespace, you can add
root: true
And put the definition of this action in the function handler.
There is a slight change in the writing. Let’s take a look and revise itmoduleA.js
, as follows:
export default {
namespaced: true,
// ...
actions: {
callAction: {
root: true,
handler (namespacedContext, payload) {
let {state, commit} = namespacedContext;
commit('setText');
alert(state.text);
}
}
}
}
In a nutshell, here’s thenamespacedContext
It is equivalent to the context object of the current module,payload
Is the parameter passed in when calling, also called load of course.
That’s all for the example. Let’s take a lookBinding function with namespace。
aboutmapState, mapGetters, mapActions
andmapMutations
How to bind these functions to modules with a namespace has already been written in the above example code. Let’s take a look at other easier ways to write them. Let’s take a look at the previous way.
Here we use the official example code to illustrate:
computed: {
...mapState({
a: state => state.some.nested.module.a,
b: state => state.some.nested.module.b
})
},
methods: {
...mapActions([
// -> this['some/nested/module/foo']()
'some/nested/module/foo',
// -> this['some/nested/module/bar']()
'some/nested/module/bar'
])
}
More elegant writing:
computed: {
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions('some/nested/module', [
'foo', // -> this.foo()
'bar' // -> this.bar()
])
}
Pass the space name string of the module as the first parameter to the above function so that all bindings will automatically use the module as the context.
We can also use
createNamespacedHelpers
Create helper functions based on a namespace. It returns an object with a new component binding auxiliary function bound to a given namespace value
import { createNamespacedHelpers } from 'vuex'
const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')
export default {
computed: {
//Search in 'some / nested / module'
...mapState({
a: state => state.a,
b: state => state.b
})
},
methods: {
//Search in 'some / nested / module'
...mapActions([
'foo',
'bar'
])
}
}
6、 Dynamic registration of modules
This chapter is quite clear on the official website, so it’s directly moved here.
After the store is created, you can use the
store.registerModule
Method dynamic registration module:
//Register module ` mymodule`
store.registerModule('myModule', {
// ...
})
//Register nested modules ` nested / mymodule`
store.registerModule(['nested', 'myModule'], {
// ...
})
And then you can go through it
store.state.myModule
andstore.state.nested.myModule
Access the status of the module.Module dynamic registration enables other Vue plug-ins to use vuex to manage state by adding new modules to the store. For example,
vuex-router-sync
Plug in combines Vue router and vuex through dynamic registration module to realize routing state management of application.You can also use it
store.unregisterModule(moduleName)
To dynamically unload the module. Note that you cannot use this method to unload static modules (that is, modules declared when the store was created).When registering a new module, you are likely to want to keep the past state, for example, from a server-side rendering application. You can go through
preserveState
Option to archive it:store.registerModule('a', module, { preserveState: true })
。
7、 Module reuse
For one thing, reuse will pollute the data state in the module, so just like data in Vue, you can use a function to declare the state.
const MyReusableModule = {
state () {
return {
foo: 'bar'
}
},
//...
}
This work adoptsCC agreementReprint must indicate the author and the link of this article