Making, blog
The vue-router is simply implemented
Vuex
Vuex centrally manages the state of all components of an application and uses rules to ensure that the state changes in a predictable manner.
Install Vuex
vue add vuex
Copy the code
The core concept
- State: indicates the status and data
- Mutations: A function that changes state
- Action: Indicates an asynchronous operation
- Store: a container containing the preceding concepts
State – the state
State Saves the application state
export default new Vuex.Store({
state: {
counter: 0}})Copy the code
<h1>
{{$store.state.counter}}
</h1>
Copy the code
Changes in state — mutations
Mutations are used to modify a state
export default new Vuex.Store({
mutations: {add(state){
state.counter++
}
}
})
Copy the code
<h1 @click="$store.commit('add')">
{{$store.state.counter}}
</h1>
Copy the code
Derived state – getters
A new state is derived from state, similar to evaluating a property
export default new Vuex.Store({
getters: {doubleCounter(state){
return state.counter * 2; }}})Copy the code
<h1>
{{$store.getters.doubleCounter}}
</h1>
Copy the code
Action – the actions
Add business logic, similar to controller
export default new Vuex.Store({
actions: {add({commit}){
setTimeout(() = > commit('add'), 1000); }}})Copy the code
<h1 @tap="$store.dispatch('add')">
{{$store.state.counter}}
</h1>
Copy the code
Vuex principle analysis
Task analysis
- Implement the plugin
- To achieve the Store class
- Maintain a responsive state state
- Implement the commit ()
- Realize the dispatch ()
- Implement getters
- Mount $store
- To achieve the Store class
Creating a new plug-in
In the SRC path of the vue2.x project, copy a store file and rename it ou-store.
Then create a new ou-vuex.js file in the ou-store path, and change vuex in the index.js file to ou-vuex.js.
import Vuex from './ou-vuex'
Copy the code
Also modify the router import in main.js.
import router from './ou-vuex'
Copy the code
Create a vUE plug-in
If you look back at store/index.js, you first registered Vuex with vue.use () and then instantiated the Vuex.Store class, so the Vuex object contains an install method and a store class.
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
...
})
Copy the code
So let’s create a new Vuex plug-in.
let Vue; // Save the Vue constructor, which is needed in the plug-in
class Store {}
function install(_Vue) {
Vue = _Vue;
}
export default {Store, install};
Copy the code
mount$store
let Vue; // Save the Vue constructor, which is needed in the plug-in
class Store {}
function install(_Vue) {
Vue = _Vue;
Vue.mixin({
beforeCreate() {
/ / mount $store
if(this.$options.store){
Vue.prototype.$store = this.$options.store; // vm.$store}}})}export default {Store, install};
Copy the code
Implement the response type savestate
data
Since state is an object, we can use new Vue() to convert the state to reactive data and save it.
Second, we can’t explicitly save the state and expose it to the outside world, so we can use get and set to save it.
class Store {
/* * options: * state * mutations * actions * modules * getters * */
constructor(options = {}) {
// data responds
this._vm = new Vue({
data: {
$$state: options.state $$state or this._vm.$data.$$state}}); }/ / for the state
get state() {
return this._vm._data.$$state;
}
// State cannot be set
set state(v) {
console.error('please use replaceState to reset state'); }}Copy the code
implementationcommit
methods
When we use commit method, it is $store.com MIT (type,payload), the first parameter is type value of mutations, the second is payload, and the parameters corresponding to mutation method are state and payload, so we implement:
class Store {
constructor(options = {}) {
this._vm = new Vue({
data: {
$$state: options.state
}
});
// Save the user configuration options for Mutations
this._mutations = options.mutations;
}
get state() {
return this._vm._data.$$state;
}
set state(v) {
console.error('please use replaceState to reset state');
}
commit(type, payload) {
// Obtain the mutation corresponding to type
const entry = this._mutations[type]
if(! entry) {console.error(`unknown mutation type : ${type}`);
return ;
}
// Pass state and payload to mutation
entry(this.state, payload)
}
}
Copy the code
implementationdispatch
methods
The dispatch method is pretty much the same as the commit method, except that the dispatch method calls the action asynchronous function, and the action takes a context and a payload, and the payload is given to the dispatch argument, The context is actually this in the instance.
But actions are used to handle asynchronous functions, so we need to bind this to the Dispatch method; Also, the action method may call the COMMIT method, so we need to bind this to the COMMIT method as well.
class Store {
constructor(options = {}) {
this._vm = new Vue({
data: {
$$state: options.state
}
});
// Save the user configuration options for mutations and Actions
this._mutations = options.mutations;
this._actions = options.actions;
// Bind the commit and Dispatch to this,
this.commit = this.commit.bind(this);
this.dispatch = this.dispatch.bind(this);
}
get state() {
return this._vm._data.$$state;
}
set state(v) {
console.error('please use replaceState to reset state');
}
commit(type, payload) {
const entry = this._mutations[type]
if(! entry) {console.error(`unknown mutation type : ${type}`);
return ;
}
entry(this.state, payload)
}
dispatch(type, payload) {
// Get the action corresponding to the type written by the user
const entry = this._actions[type];
if(! entry) {console.error(`unknown action type : ${type}`)}// Asynchronous result processing often requires a Promise to be returned
return entry(this, payload)
}
}
Copy the code
implementationgetters
The derived condition
When we define the state of getters, we are actually defining a function.
getters: {
doubleCounter(state) {
return state.counter * 2; }},Copy the code
When you use one of the derived states in getters, you actually get a value, which is the return value of the function.
<h4>double count: {{$store.getters.doubleCounter}}</h4>
Copy the code
This is actually a bit like the get property in an Object, so we can use object.defineProperty () to implement getters.
class Store {
constructor(options = {}) {
this._vm = new Vue({
data: {
$$state: options.state
}
});
this._mutations = options.mutations;
this._actions = options.actions;
this.commit = this.commit.bind(this);
this.dispatch = this.dispatch.bind(this);
// Initialize getters, which defaults to an empty object
this.getters = {};
/ / traverse options. Getters
for (const key in options.getters) {
const self = this;
Object.defineProperty(
this.getters,
key, / / the key name
{
get() {
// Call the corresponding function, with the first argument being state, and return the result
return options.getters[key](self._vm._data.$$state)
}
}
)
}
}
}
Copy the code