1. When should Vuex be used?

  • Not applicable: Using Vuex in small projects is cumbersome to write, and a simple Store mode is usually all you need.
  • Good for: Building a medium to large single-page application, Vuex can better manage state outside the component, making it easier to share state between siblings, parents, and cross-level components.

(1) Multiple views use the same state/method

  methods: {
    getData (data) {
      this.stage = data.stage
      this.$refs.detailInfo.getData(data)
      this.$refs.productInfo.getData(data)
      this.$refs.paymentPlan.getData(data)
      this.$refs.attachFile.getData()
      this.$refs.examRecord.getData()
      this.$refs.changeRecord.getData(data)
      this.$refs.contactInfo.getData(data)
      this.$refs.orderInfo.getData(data)
      this.$refs.ticketInfo.getData()
      this.$refs.paidInfo.getData()
    }
  }Copy the code

In the above code, because many subcomponents use data in the parent component, or the method call of the child component depends on the status update of the parent component, it is very tedious to write the communication method of the common parent-child component, and it is also very uncomfortable for the state transfer between the sibling components.

(2) Different views need to change the same state

<template>
  <div>
    <Card class="mgB-15 tabs-style">
      <Tabs type="card">
        <TabPane label="Details">
          <detailInfo ref="detailInfo"/>
        </TabPane>
        <TabPane :label="label.productInfo">
          <productInfo ref="productInfo" @setLabel="setLabel" />
        </TabPane>
        <TabPane :label="label.paymentPlan">
          <paymentPlan ref="paymentPlan" @setLabel="setLabel" />
        </TabPane>
        <TabPane :label="label.attachFile">
          <attachFile ref="attachFile" @setLabel="setLabel" />
        </TabPane>
        <TabPane :label="label.examRecord">
          <examRecord ref="examRecord" @setLabel="setLabel" />
        </TabPane>
        <TabPane :label="label.changeRecord">
          <changeRecord ref="changeRecord" @setLabel="setLabel" />
        </TabPane>
        <TabPane :label="label.contactInfo">
          <contactInfo ref="contactInfo" @setLabel="setLabel"/>
        </TabPane>
        <TabPane :label="label.orderInfo" :disabled="disabled">
          <orderInfo ref="orderInfo" @setLabel="setLabel" />
        </TabPane>
        <TabPane :label="label.ticketInfo" :disabled="disabled">
          <ticketInfo ref="ticketInfo" @setLabel="setLabel" />
        </TabPane>
        <TabPane :label="label.paidInfo" :disabled="disabled">
          <paidInfo ref="paidInfo" @setLabel="setLabel" />
        </TabPane>
      </Tabs>
    </Card>
  </div>
</template>Copy the code

The above code: multiple sub-components want to modify the label value of the parent component, and use the child component to throw events to change and synchronize the state of the parent component. It is so troublesome to modify just one state. When there is a lot of data to modify, it usually leads to unmaintainable code. I don’t even want to look at the code I’ve written.

2. Quickly learn the Vuex core API

Vuex five core: State, Mutations, Actions, getters, modules

  • State (auxiliary method: mapState)

Vuex uses a single state tree, and our Vue application will contain only one instance of a Store. So after we mount store to an instance of Vue, we can fetch various parts of vuex via this.$store. We can think of state as data in a single page, except that the data in state is public, global, and accessible to any component in real time. As follows:

export default new Vuex.Store({
  state: {
    username: 'admin',
    password: '123456',
    tenant: 1
  }
})Copy the code

Without the mapState function, accessing the data in state in a page would look like this: look how much trouble that is

  export default {
    name: 'Home'.mounted () {
      console.log(this.username, this.password, this.tenant)  // admin 123456 1 
    },
    computed: {
      username () {
        return this.$store.state.username
      },
      password () {
        return this.$store.state.password
      },
      tenant () {
        return this.$store.state.tenant
      },
  }Copy the code

When using the mapState helper function, it looks like this: look, this is much more comfortable

  import { mapState } from 'vuex'
  export default {
    name: 'Home'.mounted() { console.log(this.username, this.password, this.tenant) // admin 123456 1 }, computed: { ... mapState(['username'.'password'.'tenant'])}}Copy the code

Summary: What mapState really does is that when a component needs to fetch multiple states, it can be repetitive and redundant to declare those states as computed properties. To solve this problem, we can use the mapState helper function to help us generate calculated properties that will save you from pressing the key.

  • mutations(Auxiliary method: mapMutations)

export default new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    addCount (state, num) {
      state.count = num
    }
  }
})Copy the code

You can submit mutations using this. Codestore.mit (‘ method name ‘, ‘passed parameters ‘) in the component

  import { mapState } from 'vuex'
  export default {
    name: 'Home'.mounted () {
      this.$store.commit('addCount', 666) console.log(this.count) //666 }, computed: { ... mapState(['count'])}}Copy the code

The writing method of mapMutations is basically the same as the writing method of mapState mentioned above, and we mainly use the form of array here to explain. Everything is grammar sugar…

  import { mapState, mapMutations } from 'vuex'
  export default {
    name: 'Home'.mounted() { this.addCount(777) console.log(this.count) //777 }, methods: { ... mapMutations(['addCount']) }, computed: { ... mapState(['count'])}}Copy the code

  • actions(Auxiliary method: mapActions)

Actions is similar to mutations, with the difference that:

(1) The actions method is triggered through dispatch, and the state cannot be changed directly in the method, but can only be modified through the method in COMMIT.

(2) Actions can contain any asynchronous action, usually used to write common asynchronous request methods

import { query } from '@/api/index'// This is the API method to get user informationexport default new Vuex.Store({
  state: {
    userInfo: {}
  },
  mutations: {
    setUser (state, data) {
      state.userInfo = data
    }
  },
  actions: {
    getUser (context) {
      console.log(context, 'the context information')
      return query().then(res => {
        context.commit('setUser', res.data)
        return res
      })
    }
  }
})Copy the code

You can submit actions in a component using this.$store.dispatch(‘ method name ‘)

  import { mapState, mapMutations } from 'vuex'
  export default {
    name: 'Home'.mounted () {
      this.$store.dispatch('getUser').then(res => {
        console.log(this.userInfo, 'Get user login information') }) }, methods: { ... mapMutations(['setUser']) }, computed: { ... mapState(['userInfo'])}}Copy the code

The above code is printed as follows:



The writing method of mapActions is basically the same as that of mapState and mapMutations mentioned above, and we mainly use the form of array here. Everything, too, is grammar sugar…

  import { mapState, mapMutations, mapActions } from 'vuex'
  export default {
    name: 'Home'.mounted () {
      this.getUser().then(res => {     
        console.log(this.userInfo, '999') }) }, methods: { ... mapMutations(['setUser'    
      ]),
      ...mapActions([  
        'getUser']) }, computed: { ... mapState(['userInfo'])}}Copy the code

  • getters(Auxiliary method: mapGetters)

The helper function is a syntax candy, which is convenient for us to use store, since the above is too long, now we can directly use mapGetters helper method, cui花, on the code:

export default new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    addCount (state, data) {
      state.count = data
    }
  },
  getters: {
    newCount (state) {
      return state.count * 2
    }
  }
})Copy the code

The value of newCount is computed from the value of count. Get the newCount value on the page as follows:

  import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
  export default {
    name: 'Home'.mounted () {
      this.addCount(18)
      console.log(this.newCount, 'Calculated according to count') / / 36"Calculated according to count."}, methods: { ... mapMutations(['addCount']) }, computed: { ... mapState(['userInfo'
      ]),
      ...mapGetters([
        'newCount'])}}Copy the code

  • modules

Because of the use of a single state tree, all the states of an application are grouped into one large object. When the application becomes very complex, the Store object can become quite bloated. To solve these problems, Vuex allows us to split the Store into modules. Each module has its own state, mutation, action, getter, and even nested submodules

As follows:

// this is the index.js file import user from'@/store/modules/user'
import contract from '@/store/modules/contract'
export default new Vuex.Store({
  modules: {
    user,
    contract
  }
})Copy the code

Now that modules are divided, what if the method names of each module inevitably have the same name? You can fix this by setting namespaced: True to use the namespace. Details are as follows:

// This is the user.js fileexport default {
  namespaced: true,
  state: {
    count: 10
  },
  mutations: {
    setCount (state, num) {
      state.count = num
    }
  },
  actions: {
    getCount ({commit}) {
      commit('setCount', 6)
    }
  },
  getters: {
    newCount (state) {
      return state.count * 6
    }
  }
}
Copy the code

// This is contract.jsexport default {
  namespaced: true,
  state: {
    count: 20
  },
  mutations: {
    setCount (state, num) {
      state.count = num
    }
  },
  actions: {
    getCount ({commit}) {
      commit('setCount', 6)
    }
  },
  getters: {
    newCount (state) {
      return state.count * 2
    }
  }
}Copy the code

We can see that the file method names of the two store modules are all the same. After the namespace is enabled, the page is used as follows:

  import { mapState, mapMutations, mapGetters } from 'vuex'
  export default {
    name: 'Home'.mounted() { console.log(this.user, this.contract) // { count: 10} , { count: 20} console.log(this.newCount,this.newCount1); // 40 60 }, methods: { ... mapMutations(['addCount']) }, computed: { ... mapState(['user'.'contract'
      ]),
      ...mapGetters({
        newCount: 'user/newCount'// Using namespaces, you can redefine the name on the page so that the method name of each module does not conflict with newCount1:'contract/newCount',}}}Copy the code