Skip to content

Communication between Vue components

About 1044 wordsAbout 3 min

vue

2018-07-20

When we are developing a project based on Vue, data communication between components is something we must consider.

**Note: **

The implementation method in this article is to implement it without considering vuex. And only to vue@2, in vue@3, there are other better implementation solutions.

I roughly divide the relationship between components into three types:

  1. Parent-child component
<parent>
  <child></child>
</parent>

Having a similar structure, the parent component contains the child component, then the child component is the child component of the parent component, and the parent component is the parent component of the child component.

  1. Brother components
<item></item> <item></item>

The two item components are structurally the same level, and we call them brother components.

  1. Cross-multi-level components
<list>
<item>
<message><message>
</item>
</list>
<dialog>
<content></content>
</dialog>

In this structure, <list> and <message> are not direct parent-child components, and there is also a level in between. In actual scenarios, there will be component relationships across more levels. The <message> and <content> components are neither brother components nor father-son components, but cross the multi-level relationship between brothers and father-sons, and there will also be interactions in actual scenarios.

So how should we communicate with components of these three relationships?

Parent-child component communication

To talk about the communication between parent and child components, first of all, we need to understand the characteristics of the vue component.

  1. One-way data stream, data from top to bottom.

Prop is one-way bound: when the property of the parent component changes, it will be passed to the child component, but the other way around will not. This is for To prevent child components from accidentally modifying the state of the parent component to prevent the application's data flow from becoming difficult to understand.

  1. Events come from bottom to top.

The changes in the internal state of the component bubble upwards through events, notifying the previous component, the previous component listens to the event and triggers the corresponding callback.

Based on the above, the recommended way of communication between parent and child components is:

The parent component passes the state to the child component through props. The child component bubbles the state to the parent component through events. The parent component listens to trigger the callback to change the state.

parent.vue

<template>
  <div class="parent">
    <child :name="name" @name-change="nameChange"> </child>
  </div>
</template>
<script>
  import Child from './child';
  export default {
  name: 'parent',
  data () {
  return {
  name: 'Jack'
  };
  }
  methods: {
  nameChange(name) {
  this.name = name;
  }
  },
  components: {
  Child
  }
  }
</script>

child.vue

<template>
  <div class="child">
    <span>{{name}}</span>
    <button @click="onClick">change name</button>
  </div>
</template>
<script>
  export default {
    name: 'child',
    props: {
      name: {
        type: String,
        defualt() {
          return ''
        },
      },
    },
    methods: {
      onClick() {
        this.$emit('name-change', 'John')
      },
    },
  }
</script>

In some examples or personal projects, it is often found that using this.$parent in child components directly changes the state of the parent component. It is true that this method can simplify the data communication between two deeply coupled components, and it will be more convenient in some simple scenarios. However, this method is not recommended to implement parent-child component communication. The consequence of this is that it leads to the uncertainty of the data flow, sacrificing the simplicity of the single data flow, and the data changes and flow become difficult to understand.

Brother component communication, cross-multi-level component communication

There is no direct connection between these two components.

For example, if a brother component, we will naturally think of using their parent component as a relay to communicate the state of child component 1 to the parent component, and then the parent component flows to child component 2 through props, and vice versa. However, if the interaction between the brother components is complex but there is no direct interaction correlation with the parent component, the parent component assumes unnecessary responsibilities in this process.

Another example is across multiple levels of components. In the above example, there are multiple layers between <list> and <message>. If we continue to use parent-child components to communicate prop and event bubbles, the intermediate layers need to repeatedly define prop and events, which obviously also leads them to assume unnecessary responsibilities. There is no structural correlation between the <message> and <content> components, and the prop and event bubbles seem very weak and cannot directly complete communication.

So how can we complete communication between these two components without causing unnecessary interference to their intermediate hierarchical components or parent components?

Since the two component relationships are not directly related, we need to have a bridge that can directly connect them to make them related. That is, we need a middleware.

The solution given to us is vuex, but I think it is more of a global state management. Using it as a communication middleware for some two components seems to be overused, so I won't discuss it here.

The solution I took is to complete component communication using custom events.

Instantiated Vue:

vue has implemented an event system, which can be used to easily complete our component communication.

let middleware = new Vue();
export defend middleware;

message.vue

export default {
  name: 'message',
  data() {
    return {
      info: 'hello',
    }
  },
  methods: {
    sayHello() {
      middleware.$emit('say-hello', this.info)
    },
  },
}

content.vue

export default {
 name: 'content',
 data() {
 return {
 info: '';
 }
 },
 created() {
 middleware.$on('say-hello', info => {
 this.info = info;
 });
 }
}

We register the say-hello event in content.vue through middleware. When message.vue triggers the event, content.vue listens to the event triggering the callback, thus realizing state conduction.

Component data transmission is no longer transmitted through props, but communicates through events.

**If we do not use the instantiation of Vue to complete it, we can also implement a set of custom events ourselves. ** This can make more personalized custom events to meet the diverse usage scenarios in the project.

class Event {
  constructor() {
    // some props
  }
  on() {
    // do something
  }
  emit() {
    // do something
  }
  off() {
    // do somethig
  }
}

Summarize

Component communication of complex structures, and the key to implementing their communication is to implement middleware as a bridge to connect them, whether using custom events or other solutions.