Vuex and the use of several component Communications

Let's start with a simple German example

target.png

A simple application with buttons and a counter.Pressing the button increments the counter.While this is easy to achieve, the goal is to understand the basic concepts.

problem.dot.png

Suppose you have two components in your application:

1. A button (the source of the event)
2. Counters (must reflect updates based on the original event)
The two components do not know each other and cannot communicate with each other.This is a very common pattern even for the smallest Web applications.In larger applications, many components communicate with each other and must control each other.Here are some interactions with the basic to-do list:


todo.dot.png

Objectives of this article

We will explore four ways to solve the same problem:
1. Communicate between components using event broadcasts
2. Use shared state objects
3. Use vuex

First, we create components in IncrementButton at src/components/IncrementButton.vue:

<template>
  <button @click.prevent="activate">+1</button>
</template>
<script>
export default {
  methods: {
    activate () {
      console.log('+1 Pressed')
    }
  }
}
</script>

<style>
</style>

Next, we create a component for the CounterDisplay actual display counter.Let's create a new basic Vue component src/components/CounterDisplay.vue

<template>
  Count is {{ count }}
</template>

<script>
export default {
  data () {
    return {
      count: 0
    }
  }
}
</script>
<style>
</style>

Replace App.vue for this file:

<template>
  <div id="app">
    <h3>Increment:</h3>
    <increment></increment>
    <h3>Counter:</h3>
    <counter></counter>
  </div>
</template>

<script>
import Counter from './components/CounterDisplay.vue'
import Increment from './components/IncrementButton.vue'
export default {
  components: {
    Counter,
    Increment
  }
}
</script>

<style>
</style>

Now, if npm run dev runs again and opens the page in your browser, you should see a button and a counter.Clicking this button displays a message in the console

Solution 1: Event Broadcasting

solution1.dot.png

Let's modify the script in the component.First, IncrementButton.vue We use $dispatch to send a message to the parent and click the button

export default {
  methods: {
    activate () {
      // Send an event upwards to be picked up by App
      this.$dispatch('button-pressed')
    }
  }
}

At App.vue we listen to events from children and broadcast new events to all children to increase.

export default {
  components: {
    Counter,
    Increment
  },
  events: {
    'button-pressed': function () {
      // Send a message to all children
      this.$broadcast('increment')
    }
  }
}
>stay CounterDisplay.vue We listen increemnt Events and add value to the state.

export default {
  data () {
    return {
      count: 0
    }
  },
  events: {
    increment () {
      this.count ++
    }
  }
}

Some drawbacks of this approach:

1. For each operation, the parent component needs to connect and "assign" events to the correct component.
2. For larger applications, it is difficult to understand the source of events.
3. Business logic can be anywhere, which may make it impossible to maintain.

Solution 2: Shared state

Let's get back to what we did in Solution 1.We create a new file src/store.js

export default {
  state: {
    counter: 0
  }
}

Let's first modify CounterDisplay.vue:

<template>
  Count is {{ sharedState.counter }}
</template>

<script>
import store from '../store'

export default {
  data () {
    return {
      sharedState: store.state
    }
  }
}
export default store
</script>

We can modify IncrementButton.vue

import store from '../store'

export default {
  data () {
    return {
      sharedState: store.state
    }
  },
  methods: {
    activate () {
      this.sharedState.counter += 1
    }
  }
}

Solution 3: Vuex

Define a vuex.js file and introduce it into main.js

1. Introduce vuex into main.js

import Vuex from 'vuex'
import vuexs from './vuex'
Vue.use(Vuex);
const appVuex = new Vuex.Store({
    vuexs 
})
new Vue({
  el: '#app',
  router,
  appVuex ,
  components: { App },
  template: '<App/>'
})

The vuex.js file code is as follows

const state = {
 count :0
}
const mutations={
  changeMenuIndex(state, num) {
     state.count = num
  }
 }
 const actions={
    post:function(context,payload){//The context here has the same object and method as the $store we use
       return new Promise(function(resolve, reject){
         axios.post(payload.path,payload.datas).then(data=>{
            resolve(data)
         })
       });
    }
}
export default {
    state,
    mutations,
    actions
}

A state defines the variables it needs, which can only be changed by mutations or actions. Here's how to get the state variable

1. Return a state in a calculated property:

<div>{{ count }}</div>
computed: {
    count () {
      return store.state.count
    }
  }

2. mapState Auxiliary Functions

import {mapState} from "vuex";
computed: {
          ...mapState(['count'])
        },

The only way to change the state in Vuex's store is to commit a mutation.Variations in Vuex are very similar to events: each mutation has a string of event types and a callback function (handler).This callback function is where we actually make state changes, and it accepts state as the first parameter:

const mutations={
  changeMenuIndex(state, num) {
     state.count = num
  }
 }
// Used in components, num is the parameter passed in
this.$store.commit('changeMenuIndex', 10);

//The problem here is how to pass multiple parameters. mutations can only define two parameters, so they can only pass values as objects here
const mutations={
  changeMenuIndex(state, payload) {
     state.count = payload.vuexNum
  }
 }
this.$store.commit('changeMenuIndex', {
   vuexNum: 10
});
//You can also do this, type is the function name, and everything else is a parameter
store.commit({
  type: 'changeMenuIndex',
  vuexNum: 10
})

Here you can use the mapMutations auxiliary function to map the methods in the component to store.commit calls

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    // The mapMutations tool function maps the commit method in the store to the component's methods
    ...mapMutations([
      'changeMenuIndex', // Map `this.increment()` to `this.$store.commit('increment')`
      // `mapMutations` also supports loads:
      'incrementBy' // Map `this.incrementBy(amount)` to `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // Map `this.add()` to `this.$store.commit('increment')`
    })
  }
}

Action s are similar to mutation s except that:
Action s submit mutation s instead of changing states directly.
Action s can contain any asynchronous operation.

const actions={
  //how to write
  increment (context) {
      context.commit('increment')
  }
  //Writing Two
  increment ({ commit }) {
     commit('changeMenuIndex')
  }
 }
// The structure of the object is used here
//Because the parameter of a function is an object, and the function uses a method of the object, we can use the object's
//Deconstruction assignment is obtained directly to this method
//Because context itself is an object with a state object and a commit method such as
let context {
   state: {},
   commit: function(){}
}
//Depending on the object structure, the following can be defined:
let {state,commit} = context
console.log(state)//state: {};
console.log(commit)//commit: function(){};
//So inside a function is
increment ({state,commit} ) {
     commit('changeMenuIndex')
  }
//Specific es6 usage can be referenced
`http://es6.ruanyifeng.com/`

Use this. $store.dispatch ('increment', 10) in the component; as mentioned above, these are some of the things that are commonly used, and others like getter s and moudle s can see the documentation
https://vuex.vuejs.org/zh/guide/actions.html

Keywords: Vue npm axios

Added by The Saint on Fri, 17 May 2019 23:52:21 +0300