An overview,

Official document: vuex.vuejs.org/zh/

1. What is Vuex

What is Vuex? Vuex is a == state management mode developed specifically for vue.js applications.

  1. It uses == centralized storage to manage the state of all components of == applications, and rules to ensure that the state changes in a predictable manner.
  2. Vuex is also integrated into Vue’s official debugging tool, DevTools Extension, providing advanced debugging features such as zero-configuration time-travel debugging, state snapshot import and export, and more.

The terms state management, centralized storage management, and so on sound very lofty and confusing. So what exactly is state management?

You can simply think of it as storing variables that need to be shared by multiple components in one object. This object is then placed in a top-level instance of Vue and made available to other components. Then, multiple components can share all variable properties in the object, and these variable properties are == responsive ==.

2. Status management

Single interface status management

Single interface state management, also refers to vUE’s responsive state principle

  • State: Needless to say, it is our state. (You can think of it as a property in data)
  • View: View layer, which can display different information according to the change of State.
  • ActionsActions: Actions are the Actions that the user takes: clicks, inputs, and so on, that cause state changes.

Multi-interface status management

Vue already manages the state of a single interface, but what about multiple interfaces? Multiple views depend on the same state (when a state changes, multiple interfaces need to be updated). The Actions of different interfaces want to change the same state, so these states cannot belong to one view, and need a steward to help manage them. Vuex is the tool that gives us this big butler (global singleton pattern).

3. What states need to be managed

  1. The user’s login status, user name, profile picture, location information, and so on.
  2. A collection of items, items in a shopping cart, etc.

All of this state information can be stored and managed in one place, and it’s responsive

2, the State (State)

Vuex has several core concepts:

  • State
  • Getters
  • Mutation
  • Action
  • Module

1. Introduction to Vuex

The relevant Vuex configuration files are stored in the SRC/Store folder.

  1. Create an index.js file in the SRC /store folder. Use Vuex as follows:

    / / 1. Imported
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    // 2. Install the plug-in
    Vue.use(Vuex)
    
    // 3. Create an object and export it
    export default new Vuex.Store({
      state: {
        // Define attributes to hold the shared state
        count: 0
      },
      mutations: {
        Mutations change the state, which can be monitored by DevTools for easy debugging
        // By default, the method takes a parameter called state
        decrement(state){ state.count--; }},actions: {},modules: {}})Copy the code
  2. Main.js mounts Vuex to the Vue instance, ensuring that it is available to all components

    import Vue from 'vue'
    import App from './App'
    import store from './store'
    
    Vue.config.productionTip = false
    
    new Vue({
      el: '#app',
      store,
      render: h= > h(App)
    })
    Copy the code
  3. Use the shared state in Vuex

  • == Access status == : YesThis $store. State. Properties
  • == Modified status == : ApprovedThis.codestore.com MIT (' method in mutation ')

2. State Indicates a single State tree

Vuex proposed the use of Single state tree, the English name is Single Source of Truth, which can also be translated into a Single data Source. That is, all data is stored in a Store object

If your state information is stored in multiple Store objects, it will be particularly difficult to manage, maintain, and so on.

So Vuex uses a single state tree to manage all states at the application level. A single state tree allows us to find a fragment of a state in the most direct way, and in the later maintenance and debugging process, it can also be very convenient to manage and maintain.

Getters (” compute properties “)

Getters is similar to computed in VUE

  1. The first argument is State

    const store = new Vuex.Store({
      state: {
        todos: [{id: 1.text: '... '.done: true },
          { id: 2.text: '... '.done: false}},getters: {
        doneTodos: state= > {
          return state.todos.filter(todo= > todo.done)
        }
      }
    })
    Copy the code

    Get the value in Getters:

    {{$store.getters.doneTodos}}
    
    // In the vue instance:
    this.$store.getters.doneTodos
    Copy the code
  2. The second parameter is Getters

    getters: {
      // ...
      doneTodosCount: (state, getters) = > {
        return getters.doneTodos.length
      }
    }
    Copy the code
  3. Let the getter return a function that implements passing parameters to the getter

    getters: {
      getTodoById(state) {
        return function (id) {
          return state.todos.find(s= > s.id === id)
        }
      }
    }
    // Abbreviated 1:
    getters: {
      getTodoById(state) {
        return id= > {
          return state.todos.find(s= > s.id === id)
        }
      }
    }
    // Short for 2:
    getters: {
      getTodoById: (state) = > (id) = > {
        return state.todos.find(s= > s.id === id)
      }
    }
    Copy the code

    Get the value in Getters:

    {{$store.getters.getTodoById(2)}}
    
    // In the vue instance:
    this.$store.getters.doneTodos
    Copy the code

Iv. Mutations (synchronous update state)

1. Update status

The only way to change the state in Vuex’s Store is to submit mutation==.

Each mutation has a string of == event type == (type) and a == callback function == (handler).

  • Event type: the name of the function defined in mutation
  • The callback function: refers to the parameter and body of the function. The first parameter of the callback function isstate

Mutations are defined:

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // Change the status
      state.count++
    }
  }
})
Copy the code

Status update:

this.$store.commit('increment')
Copy the code

2. Pass-through parameter (Payload)

When updating data with mutation, it’s possible that we want to carry some additional parameters that are called the Payload of the mutation

// ...
mutations: {
  increment (state, n) {
    state.count += n
  }
}
Copy the code
this.$store.commit('increment'.10)
Copy the code

In most cases, the payload should be an object, so that it can contain multiple fields and that the mutation recorded is easier to read:

// ...
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
Copy the code
this.$store.commit('increment', {
  amount: 10
})
Copy the code

3. Object style submission

Another way to commit a mutation is to use an object that contains the type attribute directly:

this.$store.commit({
  type: 'increment'.amount: 10
})
Copy the code

When an object-style commit is used, the entire object (including the type attribute) is passed to the mutation function as a payload, so the handler remains the same:

mutations: {
  // The entire object submitted above is passed to payload
  increment (state, payload) {
    console.log(payload);
    state.count += payload.amount
  }
}
Copy the code

4. Response rules

Since the state in Vuex’s Store is responsive, the Vue component that monitors the state is also automatically updated when we change the state. This also means that mutation in Vuex is subject to the same precautions as when using Vue:

  1. Initialize all required properties in your store in advance.

  2. When we need to add new properties to an object:

    // 1. Use vue.set
    Vue.set(obj, 'newProp'.123)
    
    // 2. Replace the old object with a new onestate.obj = { ... state.obj,newProp: 123 }
    Copy the code
  3. Deletes a property on an object

    Vue.delete(obj, 'oldProp')
    Copy the code

5. Replace the Mutation event type with constants

Substituting constants for mutation event types is a common pattern in various Flux implementations. This allows tools like Linter to work, and keeping these constants in separate files allows your code collaborators to see exactly what mutations are included in the entire app:

  1. Define a constant and export it
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
Copy the code
  1. Import constants, pass[]To use a constant as a function name
// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'

const store = new Vuex.Store({
  state: {... },mutations: {
    // We can use the ES2015 style named properties function to use a constant as the function name
    [SOME_MUTATION] (state) {
      // mutate state}}})Copy the code
  1. Use the constant name when submitting
import { SOME_MUTATION } from './mutation-types'

this.$store.commit( SOME_MUTATION )
Copy the code

6. Mutation must be a synchronization function

An important rule to remember is that ==mutation must be a synchronous function ==.

For each mutation to be recorded, DevTools needs to take snapshots of the previous state and the later state. If the mutation is an asynchronous function, DevTools does not know when the callback function was actually called and will not take a snapshot of the latter state.

Therefore, if the operation is asynchronous, use Action

5. Actions (Asynchronous status updates)

Action is similar to mutation, except that:

  • ActionIs submittedmutationInstead of changing the state directly.
  • ActionAny asynchronous operation can be included.

Definition 1.

  1. actionsBy default, the first parameter of the defined function iscontextObject, this object is an object withstoreInstance An object that has the same methods and properties
    1. context.commit(): Submit onemutation
    2. context.state: getstate
    3. context.getters: getgetters.
    4. The second parameter is the payload, the same as the second parameter in mutation
  2. If you want to modify in an asynchronous operationstateIn the state that needs to passmutations
const store = new Vuex.Store({
  state: {
    counter: 1000,},mutations: {
    decrement(state) {
      state.counter--
    }
  },
  actions: {
    // Context: context
    aDecrement(context, payload) {
      setTimeout(() = > {
        console.log(payload);
        context.commit('decrement')},1000)}}}Copy the code

2. Dispatch

In the Vue component, methods in the action are called through Dispatch

// Direct distribution with no parameters
this.$store.dispatch('aDecrement')

// Distribute as a payload
this.$store.dispatch('aDecrement', {
  amount: 10
})

// Distribute as objects
this.$store.dispatch({
  type: 'aDecrement'.amount: 10
})
Copy the code

3. Return to the Promise

In an Action, we can place an asynchronous operation in a Promise and call resolve or reject upon success or failure

actions: {
  aDecrement(context, payload) {
	return new Promise((resolve, reject) = > {
	  setTimeout(() = > {
	    context.commit('decrement');
	    console.log(payload);
	
	    resolve('You can pass arguments')},1000)}}}Copy the code

Call this method:

this.$store
  .dispatch('aDecrement'.'I am the message')
  .then(res= > {
    console.log('There's a submission done.');
    console.log(res);
  })
Copy the code

6. Module

Vue uses a single state tree, which means that many states are managed by Vuex. When the application becomes very complex, the Store object can become quite bloated.

To solve this problem, Vuex allows us to divide the Store into modules, each of which has its own state, mutations, actions, getters, etc

1. Module structure

  1. In the modulemutationThe first parameter of “state” is the (local) state of the current module
  2. In the moduleaction, the local state passes throughcontext.stateIs exposed, the root node state iscontext.rootState
  3. In the modulegetterThe first parameter state is also local state, and the third parameterrootStateIs the state of the root node
  4. throughmodulesIntroduce the defined module
const moduleA = {
  state: () = > ({
    count: 0
  }),
  mutations: {
    increment (state) {
      // The 'state' object here is the local state of the module
      state.count++
    }
  },

  getters: {
    doubleCount (state, getters, rootState) {
      return state.count * 2}},actions: {
    incrementIfOddOnRootSum ({ state, commit, rootState }) {
      if ((state.count + rootState.count) % 2= = =1) {
        commit('increment')}}}}const moduleB = {
  state: () = >({... }),mutations: {... },actions: {... }}const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})
Copy the code

2. Access the data in the module

  1. To access state in a module, run store.state. Module name. Local state name

    {{$store.state.a.name}}
    Copy the code
  2. Getters, mutations and Actions in the access module are directly accessed without change

    $store.commit('increment')
    
    $store.getters.doubleCount
    
    $store.dispatch('incrementIfOddOnRootSum')
    Copy the code

3. Project structure

Vuex does not restrict code structure. However, it lays down some rules to follow:

  1. Application-level state should be concentrated in a single Store object.

  2. Submitting mutation is the only way to change the state, and the process is synchronous.

  3. All asynchronous logic should be encapsulated in actions.

├── index.html ├── main.js ├── API │ ├─...# Extract API request├── Components │ ├── app.vue │ ├─... └ ─ ─ store ├ ─ ─ index. Js# Where we assemble the module and export the store├ ─ ─ actions. Js# Root level action├ ─ ─ mutations. Js# root-level mutation└ ─ ─ modules ├ ─ ─ cart. Js# Shopping cart module└ ─ ─ products. Js# Product module
Copy the code

other

1. Deconstruction of objects

Defining an object

const obj = {
  id: '123'.name: 'Joe'.age: 23
}
Copy the code

To retrieve properties from this object, use the following method:

// Get the value based on whether the variable name matches the property name in the object
let {name, age} = obj;
Copy the code

In this way, you can quickly fetch the attributes you want from the object. Make sure that the variable name is the same as the object property name.

If the parameter is passed to an object but only some of its properties are needed, we can write:

getObjParam({name, age}){
  console.log(name);
}
Copy the code