At the heart of Vue, componentization saves us a lot of development work. The page serves as a container for components that can be nested and combined at will. But each component is a closed space, in a page, we often need to do the linkage between the components, this time we need to carry on the communication between components. We usually use different communication methods based on the relationship between components, as shown in the figure above. The relationship between components can be as follows:

Parent-child communication

As shown in the figure, the relationship between parent component A and child components B and C is the parent-child component relationship, which is also the most common component relationship in our development. In this case, we can communicate in the following ways:

1. props/$emit

The parent component passes parameters to the child component using v-bind:key=” XXX “/ :key=” XXX”, and the child component uses props to receive the parameters. $emit = $emit = $emit = $emit = emit = $emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit = emit Here’s an example of how to use it:

// Parent Parent. Vue <template> <div id="app"> <children :names="names" @submit="submit"></children> </div> </template> <script> import children from "./components/children" export default { components:{ "users":Users }, data(){ return{ names:["Henry","Bucky","Emily"] } }, methods: { submit(data) { console.log(data) } } }Copy the code
<template> <div class="hello"> <ul> <li v-for="name in names">{{name}}</li> </button> </div> </template> <script> export default {name: 'HelloWorld', props:{names:{// this is the name of the parent tag type:Array, required:true}}, methods: {submitCount() {this.$emit('submit', names.length)}}} </script>Copy the code

2.$parent / $childrenwithref

  • ref: If used on a normal DOM element, the reference refers to the DOM element. If used on a child component, the reference points to the component instance
  • $parent / $children: Access the parent/child instance

Both take the component instance directly and use it to call the component’s methods or access data directly. Let’s look at an example of using a ref to access a component:

Export default {data () {return {title: 'vue.js'}}, methods: { sayHello () { window.alert('Hello'); }}}Copy the code
// parent <template> <component-a ref="comA"></component-a> </template> <script> export default {mounted () {const comA =  this.$refs.comA; console.log(comA.title); // vue.js accesses the data of the corresponding component instance in coma.sayhello (); }} </script>Copy the code

$children can be used to access child components in the parent component, but it is important to note that this.$children gets an array of component instances, which is unordered and not responsive. This makes it impossible to explicitly find the child component, so it is not recommended. $parent Level-1 parent instance of the current component tree. If the current instance does not have a parent, the instance will be itself.

Sibling communication

Child components B and C in the figure are what we call sibling components, they have a common parent component. Because of this common parent bridge, we can communicate with siblings using the props/$emit and $ref combination described above:

$emit('submit', data) = $emit('submit', data) = $emit('submit', dataCopy the code
// A < child-b @submit="submit"></ child-b ></ child-c ref="child_c"></ child-c >... Methods: {submit(data) {this.$refs.child_c.acceptBmsg(data)}}Copy the code
// subcomponent C methods: {acceptBmsg(data) {console.log(data)}}Copy the code

Although this can also achieve the communication between sibling components, after all, after a forwarding of the parent component, the parent component needs to add some forwarding logic code. If we had more of this in our project, we would need to write forward logic in each parent component, which would lead to code clutter. At this point, we can use EventBus(also called EventBus) to unify management.

3.EventBus

This method uses an empty Vue instance as the central event bus (event center), which can be used to trigger and listen for events, cleverly and lightly to communicate with any component, including parent, sibling, intergenerational, and stranger components. It’s kind of a publish, subscriber model. One component can be published and several components can be subscribed. Multiple component publishing, one component subscription; Multiple component publishing, multiple component subscription. The implementation is as follows:

Create a new bus.js file in the directory, create and output an empty Vue instance

//bus.js
import Vue from 'vue'

const bus = new Vue();
export default bus
Copy the code

Scenario: Component A sends A message to component B

// <template> <div> <script> import {EventBus} from </button> </template> <div> <script> import {EventBus} from </button> </template> <div> <script './bus.js' export default { data(){ return { name: 'LiLei' } }, methods: { send(){ EventBus.$emit('sengMsg', this.name) } } } </script>Copy the code
<script> import {EventBus} from './bus.js' export default {mounted(){EventBus.$on('sengMsg',(data)=>{ console.log(data) }) } } </script>Copy the code

Grandfather and grandson components communicate

In our actual development, we will encounter another situation where we have multiple layers of nested components, such as the relationship between component A and component D in the beginning diagram. Normally, the parent component passes data to the grandson component, either by using the parent props layer or by using EventBus. After Vue2.2.0, Vue also provides provide/inject options.

This pair of options allows an ancestor component to inject a dependency into all of its descendants, no matter how deep in the component hierarchy, for as long as the upstream and downstream relationships are established.

In other words, as long as the parent component declares provide, it can interact with its child component, grandson component, great-grandson component and other components that can form upstream and downstream relationship, no matter how deep the data in the provider can be accessed through inject. Rather than being limited to the current parent component’s Prop property. Note that it is only a one-way transmission from ancestor to offspring. Someone described it this way:

Provide is equivalent to the enhanced parent component prop that can span intermediate components, while Inject is equivalent to the enhanced child component prop

Usage:

  • Provide provides variables: Object | () => Object
  • Inject a variable: Array<string> | { [key: string]: string | Symbol | Object }

The provide option should be an object or a function that returns an object. This object contains properties that can be injected into its descendants. In this object, it supports the Symbol in ES6 as a key, but only works in environments such as native support.

The inject option can be

  • An array of strings

  • An object whose key is the local binding name and whose value is:

    • Used in search of available injected contentkeyOr,
    • An object whosefromProperty is used to search the available injected contentkey.defaultProperties are used in the case of degradationvalue

Tip: Provide and inject bindings are not responsive, this is intentional, however, if you pass in an object that can be listened to, then that object’s properties are still listened to. (In use we often pass in the entire component instance)

Responsive provide can be optimized using the latest Vue 2.6 API vue.Observable (recommended)

// parent component <template> <div> <p>{{title}}</p >< son></son> </div> </template> <script> import son from "./son" export Default {name: 'Father', components: {Son}, // provide option provide variable provide: {message: Provided by father}, data () {return {title: 'parent'}}, methods: {... } } </script>Copy the code

We don’t do anything in the child component

</div> <p> < {title}}</p >< grand-son></grand-son> </div> </template> <script> import grandSon from "./ morat "export default {name: "Son", components: {morat}, data () {return {title: 'child'}},}; </script>Copy the code

In the grandson component, we receive data from the parent component provide via inject

<div> <p>message: {{message}}</p > </div> </template> <script> export default {name: "GrandSon", "GrandSon", data () {return {title: 'GrandSon'}}, methods: {... }}; </script>Copy the code

Unfamiliar component communication

All of the above cases are related components communicating, so what kind of communication should we use for unrelated components? In fact, the above mentioned EventBus is already capable of communicating between unfamiliar components. But Vue also provides the more powerful Vuex(state Management Mode) to share state between multiple components.

Vuex member List:

  • State Storage state
  • Mutations state member operation
  • Getters processes state members to the outside world
  • Actions Asynchronous operations
  • Modules Modules status management

Briefly introduce the functions of each module in the process:

  • Vue Components: Indicates the Vue Components. HTML page, responsible for receiving user actions and other interactive behavior, execute the dispatch method to trigger the corresponding action for response.
  • State: Page state management container object. The scattered data of data objects in Vue Components is stored in a centralized manner, which is globally unique for unified state management. The data required for the page display is read from this object, utilizing Vue’s fine-grained data response mechanism for efficient status updates.
  • Getters: State object reading method. This module is not listed separately in the figure and should be included in render. Vue Components uses this method to read the global state object.
  • Dispatch: The operation behavior triggering method. It is the only method that can execute an action.
  • Actions: Action behavior handling module, triggered by $store.dispatch(‘action name ‘, data1) in the component. Commit () then triggers the call to mutation, indirectly updating the state. Is responsible for handling all interactions received by Vue Components. Contains synchronous/asynchronous operations, supports multiple methods of the same name, and fires in the order in which they are registered. The operations requested to the background API are performed in this module, including triggering other actions and submitting mutations. This module provides encapsulation of promises to support chained triggering of actions.
  • Commit: Indicates how to commit a state change. Submitting the mutation is the only way to execute the mutation.
  • Mutations: Method of state change operation, triggered by COMMIT (‘mutation name ‘) in actions. Is the only recommended way for Vuex to modify state. This method can only be synchronized, and the method name must be globally unique. During the operation, some hooks will be exposed for state monitoring and so on.

If you want to learn how to use Vuex systematically, see # Vuex

Conclusion:

We have described several ways to communicate between components, but in addition to learning how to use them, it is more important to understand which communication methods are suitable for which scenarios. If your project is a simple application, using Vuex can be tedious and redundant. That’s true — if your application is simple enough, you’re better off not using Vuex. A simple Store mode (such as a new window) should suffice. However, if you need to build a medium to large single-page application, you are likely to be thinking about how to better manage state outside of components, and Vuex would be a natural choice. All roads lead to Rome, but the most important thing is that you find the nearest and least effort one.

Shakespeare said that a comrade who does not like after watching is not a good comrade