Official explanation: Vuex is a state management mode developed specifically for vue.js applications.
1, What does Vuex do?
What is state management?
To put it simply: you can store all the variables required by multiple components in an object, and then put the object in the vue instance at the top level so that other components can use it. In this way, multiple components can share all the properties in this object.
Some students thought that if we define an object at the vue top level, we can share it? We found that although the data can be obtained, if the data changes in a component, how can we modify the data to keep it up-to-date in other components?
Our vuex is to provide a plug-in to share state among multiple components, and can realize real-time response.
2, Vuex use
vuex is a plug-in to manage the communication between components, so it must be installed before use.
2.1 installation
1> Using script to import
<script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>
2> Using package management
npm install vuex --save //yarn add vuex
Note: vuex must rely on vue
2.2. Building store instances
Create a store folder and create a new index.js
import Vue from "vue"; import Vuex from "vuex"; Vue.use(Vuex);//Using vuex export default new Vuex.Store({ state:{}, mutations:{}, getters:{}, actions:{}, modules:{} })
At main.js, mount the store
import store from './store' new Vue({ router, render: h=>h(App) }) //amount to // Vue.prototype.$store = store
2.3 service status
// State defined in store state:{ statue: 'on-line' } //Use within components <div>In component data:{{ $store.state.status }} </div> //Use in js mounted(){ console.log( this.$store.state.status ) }
3, Vuex's five cores
3.1,state
state stores the basic data of vuex and is used to store variables.
Single state tree
Vuex uses a single state tree, that is, one object contains all the state data. State, as a constructor option, defines all the basic state parameters we need.
How to reference state data in a component:
1> Get the state of vuex through vue's computed
export default new Vuex.Store({ state:{ online:true } }) computed:{ status(){ return this.$store.state.online } }
When the data in the store changes, the calculation properties will be re evaluated and the relevant DOM will be updated.
2> If we need to use multiple parameters, using computed to calculate the attribute will make the code redundant and complex. At this time, we can use the mapState auxiliary function.
//There are a lot of data in state, which is referenced in a component export default new Vuex.Store({ state:{ online:true, per:[ {name:'qq',age:18} ], role:'administrators' } }) //In assembly import { mapState } from 'vuex' export default { name: 'App', computed: mapState({ online: state => state.online, per: 'per', // 'per' is equivalent to state.per role: 'role' // 'role' is equivalent to state.role }) }
vuex uses a single state tree to manage all States at the application level. The single state tree allows us to find fragments of a state in the most direct way, and the subsequent maintenance and debugging process can also be very convenient for management and maintenance.
3.2,getters
Get some state mutated states from the store.
There are generally two ways to use it:
1> The returned results depend only on the data in state
export default new Vuex.Store({ state:{ count:2, }, getters:{ //Return 2x data of count countDouble(state){ return state.count*2 } } }) //Reference in component <div> obtain countDouble: {{ $store.getters.countDouble }} </div> //Operation results obtain countDouble: 4
Here, the use of $store.getters.countDouble is the same as that of $store.state.count above.
2> The mutation result returned in getters depends on the result returned by a property in getters
export default new Vuex.Store({ state:{ count:2, }, getters:{ //Return 2x data of count countDouble( state ){ return state.count * 2 } //Return double data of countDouble countDoubleT( state , getters ){ return getters.countDouble * 2 } } }) //Reference in component <div> obtain countDouble: {{ $store.getters.countDoubleT }} </div> //Operation results obtain countDouble: 8
3.3,mutations
The only way to update the store status of vuex: submit Mutation.
Movements mainly consists of two parts:
- Event type of string
- A callback function whose first parameter is state.
1> . the method in mutation is called through commit without passing parameters. Use:
export default new Vuex.Store({ state:{ count:2, }, mutations:{ incrs(state){ // count plus 1 state.count++ } } }) //Component call <button @click=" $store.commit('incrs') " >+</button> {{$store.state.count}}
Each time the button is clicked, the count will be added by itself.
2> Variations pass parameters
When we click the Add button, we specify the added value for each click, as follows:
export default new Vuex.Store({ state:{ count:2, }, mutations:{ addNum( state,n ){ // count plus 1 state.count +=n } } }) //Component call <button @click=" $store.addNum( 'incrs' , 5 ) " >+</button> {{$store.state.count}} //Operation results Every time you click the button, count Add 5
The last instance passed a parameter. If we need to pass multiple parameters, how can we implement it?
3> Variations passes multiple parameters
export default new Vuex.Store({ state:{ count:2, }, mutations:{ addNum(state,payload){ // payload is the parameter object passed in state.count += payload.count } } }) //Component call <button @click="addTen" >Plus 10</button> {{$store.state.count}} export default{ methods:{ addTen(){ this.$store.commit({ type:'addNum', count:10, ...//You can pass any number of parameters }) } } } //Operation results Every time you click the button, count Add 10
The above method is a special submission package for mutations. The object containing the type attribute uses the entire commit object as a payload.
3.4,actions
The method of submitting update data must be synchronous. If it is used asynchronously, there will be problems. Then asynchronous update is often used in project development, such as network request data.
Actions is similar to mutation and has roughly the same functions, but actions is used to replace mutations for asynchronous operations.
1> Basic use of actions
actions:{ aUpdateCount(context){ setTimeout(()=>{ //Simulating asynchronous operations using timers context.commit('updateCount') },2000) } }, mutations:{ updateCount(state){ state.count = 5201314 }, } // Used in components {{$store.state.count}} <button @click="$store.dispatch('aUpdateCount')">Asynchronous update count</button> //Operation results Click the button to update in two seconds count The value is 5201314
It is worth noting that when using actions to update data asynchronously, you still need to go through the methods in changes. The data in state can only be modified by the methods in changes.
Call the method in mutations and call it with commit.
Call the method in actions and call with dispatch.
2> You can also take parameters when updating asynchronously
// Function: click the button to specify the modified value of count actions:{ aUpdateCount( context, payload ){ setTimeout(()=>{ //Simulating asynchronous operations using timers context.commit( 'updateCount' , payload ) },2000) } }, mutations:{ updateCount( state , payload ){ state.count = payload }, } // Used in components {{$store.state.count}} <button @click="$store.dispatch( 'aUpdateCount', 'I love the front end' )">Asynchronous update count</button> //Operation results Click the button to update in two seconds count Value is: I love the front end
3> Incoming asynchronous parameters
actions:{ //Incoming promise updateData(context,payload){ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('I have learned it.') },2000) }) }, } //Intra component call <button @click="ok">promise Successful execution, return"I have learned it."</button> methods:{ ok(){ this.$store.dispatch('updateData').then((res)=>{ console.log(res) }) }, } //Operation results Click the button and print in two seconds: I learned
3.5,modules
Modules means modules. vue uses a single state tree. The project is getting larger and larger, and there are more and more data in the store. It is not convenient for data management and maintenance, and the code will become bloated. Therefore, using modules to divide the data into corresponding modules not only facilitates development, but also improves the readability of the code.
1> modules is easy to use
import Vue from 'vue' import Vuex from 'vuex' import { Increase } from './mutation_type.js' Vue.use(Vuex) export default new Vuex.Store({ state: {}, actions: {}, getters: { }, mutations: { }, modules:{ a:{ state:{}, getters:{}, mutations:{}, actions:{} }, b:{ state:{}, getters:{}, mutations:{}, actions:{} } }, }) //It can also be sorted into const moduleA = { state:{}, getters:{}, mutations:{}, actions:{} } const moduleB = { state:{}, getters:{}, mutations:{}, actions:{} } Vue.use(Vuex) export default new Vuex.Store({ state: {}, actions: {}, getters: { }, mutations: { }, modules:{ a: moduleA, b: moduleB }, })
2> How to use the data in the module?
const moduleA = { state:{ aName:'I am the module a Data' }, getters:{}, mutations:{}, actions:{} } // Intra component reference {{ $store.state.a.aName }}
3> How to call the method in the changes in the module?
$store.commit('aChangeName')
As like as two peas in the mutations before retrieving the module, the program first looks up the method from the first store, and then continues to search the module when it fails to find the method.
4> Call getters method in module
$store.getters.getName
It should be noted that the methods in getters mutate the data in state. What if the getters method of the module needs the state in the root store?
getName(stateļ¼getters , rootState){ // State indicates the state of the current module // Getters represents getters of the current module //rootState represents the state in the root store }
5> For the methods in actions in the module, when using commit to call the methods in changes, you can only call the changes method in the module, not the methods in the outer layer.
4, Vuex data response principle
The state in vuex's store is responsive. When the data in the state changes, the vue component will update automatically. This requires us to abide by some vuex corresponding rules:
Initialize the required properties in the store in advance.
In human words, only the attributes defined in state can be responsive. If they are added or deleted later, they cannot be responsive.
For example, chestnuts:
mutations:{ changeName(state){ state.info.name = 'People who love learning' }, addAdrs(state){ state.info['address'] = "Xi'an, Shaanxi" }, } {{this.$store.state.info}} <button @click="$store.commit('changeName')">Modify name</button> <button @click="$store.commit('addAdrs')">Add address</button>
At this time, when you click to modify the name, you can be responsive. When you click the "add address" button, the page does not respond, but you can see the data change in the developer mode.
If we want to be responsive, how can we achieve it?
addAdrs(state){ state.info['address'] = "Xi'an, Shaanxi" //Amend to read: Vue.set(state.info,'address','Xi'an, Shaanxi') },
Similarly, if you want to delete the age attribute, you can't use delete to respond. You need to modify it to Vue.delete.
Instance: responsive deletion of age attribute
deleteAge(state){ //delete state.info.age //Change to Vue.delete(state.info,'age') }, //Component content {{this.$store.state.info}} <button @click="$store.commit('deleteAge')">Delete age</button>
5, Type constant
Many event types are defined in mutation, that is, method names. When the project becomes larger and larger, Vuex manages more and more states and needs to update more and more states. This means that there are more and more method names in changes. When there are too many methods, you need to spend a lot of energy to remember or switch files back and forth to find the method name, which is easy to make mistakes. Therefore, it is recommended that you use a constant, even if the method name is wrong, It will also make mistakes, and the program will not have exceptions.
For example:
// New mutation_type.js file //Export a constant export const Increase = 'increase' // store.js file import Vue from 'vue' import Vuex from 'vuex' import { Increase } from './mutation_type.js' Vue.use(Vuex) export default new Vuex.Store({ state:{ count:2, }, mutations:{ [Increase](state){ state.count++ }, } }) //Component content {{ $store.state.count }} <button @click="add">Plus 10</button> import { Increase } from './store/mutation_type' sxport default{ methods:{ add(){ this.$store.commit(Increase) } } }
When using, just remember Increase or mutation_ Just look in the type.js file.