preface

It is believed that students who have used VUE in practical projects must be familiar with the communication between father and son components in VUE. Vue adopts good data communication mode to avoid the confusion caused by component communication. Today, I will share with you the communication mode between VUE father and son components, advantages and disadvantages, and its application scenarios in practical work

First of all, let’s think with these questions in mind

How many parent-child component communication modes are there in vUE?

What is the best way for parent and child components to communicate in VUE?

3 What are the application scenarios of each communication mode in the VUE?

A prop

1 Basic Usage

This is the most common type of parent component communication. We can bind properties and methods to the child component directly in the tag. For properties, we can get them directly from the child component’s declared prop.

Let’s briefly write a scenario where the props parent component communicates

The parent component

<template> <div class="father" > <input v-model="mes" /> <button @click="send" > {{ sonMes }}</div> <son :fatherMes="sendSonMes" @sonSay="sonSay" /> </div></template><script>import son from './son'export default {name:'father', components:{son /* child components */}, data(){return {mes:', sendSonMes:', }}, methods:{/* send(){this.sendsonmes = this.mes}, SonSay (value){this.sonMes = value},},}</script>Copy the code

All we need to do here is pass the data fatherMes for the child component and the method sonSay for the child component as tags.

Child components

<template> <div class="son" > <div> Parent component says to me: {{fatherMes}} </div> <input V-model ="mes" /> <button @click="send" >< /button> </div> </template><script>export default { name:'son', props:{ fatherMes:{ type:String, default:'' } }, data(){ return { mes:'' } }, methods:{ send(){ this.$emit('sonSay',this.mes) } }, }</script>Copy the code

The child component uses props to accept events from the parent component, so we can use this.$emit to emit events from the parent component.

Distinguish the React props

The React component is updated because the props are updated and its state changes. When the React component changes, the components are updated by default. In Vue, if we don’t do dependency collection (template collection, computed property collection) on the new props passed by the parent component, the component doesn’t touch the update.

The effect

Data to monitor

We can use watch to listen for changes in the props from the parent component when we don’t want to update the view based on changes in the props, or when we don’t want to update the view immediately.

watch:{    fatherMes(newVaule){        console.log(  newVaule)     }}
Copy the code

2 advantages

The advantages of props passing data are obvious. It is flexible and simple, and can calculate properties of props data, and perform data monitoring. Communication between parent and child components is flexible and convenient. This could be just a father-son level.

Three shortcomings

1 props to tamper with

When we use the parent props in the child component, if some variable assignment or modification operations are involved, the props is somehow modified, and the data of the parent component is also tampered with. Some students may be confused. The parent element props cannot be modified. Can props change in vue? If props is the base datatype, we will expose an error when we change it. Let’s look at an example.

The parent component

<template> <div> <div> parent </div>< son :fData="sonProps" /> </div></template><script>import son from './sTampering'export default { name:'father', components:{ son }, data(){ return { sonProps:'' } },}</script>Copy the code

Child components

<template> <button > alter parent component props</button></template><script>export default {name:'son', props:{ fData:{ required:true } }, methods:{ changFatherProps(){ this.fData = 'hello ,father' } }}</script>Copy the code

The following alarm is raised when we click the button directly.

But when we pass a reference datatype and modify an attribute of the datatype.

The parent component

data(){    return {        sonProps:{            a:1,            b:2        }    }}
Copy the code

Child components

changFatherProps(){  
  this.fData.a = 'hello,world'
}
Copy the code

No error is reported when the button is clicked.

So we print the sonprops data for the parent component:

We found that the parent component’s data data has been tampered with by the quilt component. We conclude that a child cannot reassign a prop directly to its parent, but when the parent is of reference type, it can modify the properties under the props of the parent. This is an awkward situation, and it is acceptable if we design for the parent data to be modified at the same time, but it is a serious logic bug when we don’t want any changes to the parent data source. So that’s one of the risks of the PROPS communication.

2. Cross-layer communication is difficult for sibling components

For parent-child-child communication across hierarchies, we obviously need layer by layer of prop binding properties and methods, which can be difficult to implement in more complex cases.

For communication between sibling components, props needs to use the parent component as a bridge to implement the communication mode of child component -> parent component -> child component. If the parent component is used as the medium, the parent component must be re-rendered, which requires a high cost to implement the communication between sibling components.

4 Application Scenarios

The application scenario for props is simple, that is, normal parent-child components that are not deeply nested communicate with sibling components that have less complex relationships.

2 this. $XXX

Fetching a vue instance directly from the data under this is a bit violent, because a component is ultimately an object that holds various information about the component, and the component is associated with the this.$children and this.$parent Pointers. Because there is only one root component in the project, it is theoretically possible to access any component on the page through this.$children this.$parent.

1 Basic Usage

The parent component

<template> <div class="father" > <input v-model="mes" /> <button @click="send" > The <div> child component said to me: {{ sonMes }}</div> <son /> </div></template><script>import son from './son'import son2 from './son2'export default { Name :'father', components:{son,/* subcomponent */ son2}, data(){return {mes: ", sendSonMes: ", /* Information from child components */ sonMes: "/* Information sent to child components */}}, } / currentChildren = this.$children[0]} / currentChildren = $children[0] Currentchildren.accept (this.mes)}, /* Accept (value){this.sonmes = value}},}</script>Copy the code

Child components

<template> <div class="son" > <div> Parent component says to me: {{fatherMes}} </div> <input V-model ="mes" /> <button @click="send" >< /button> </div> </template><script>export default { name:'son', data(){ return { mes:'', fatherMes:'' } }, */ accept(value){this.fathermes = value}, / * send information to the parent component * / the send () {this. $parent. Accept this. (mes)},,}} < / script >Copy the code

The effect

This.$parent, this.$children, functions, functions, functions, functions, functions, functions, functions, functions, functions Communication between components can be realized, which seems very convenient, but in practice there are great disadvantages, and VUE itself does not advocate this way of communication. There are also many risks associated with this form of communication, as we’ll explain later.

2 advantages

This.$children,this.$parent this.$refs this.

Three shortcomings

1. This. Children are uncontrollable and have certain risks

In the example above, if we make minor changes to the parent component, an error will be reported directly.

Before the

<son2 v-if="false" />
Copy the code

to

<son2 v-if="true" />
Copy the code

$children[0] = son2; $children[0] = son2; son2 = son2; This.$children is not recommended for v-if dynamic control components to display hidden. Instead, we can use ref to get the instance of the corresponding child component.

The above change

<son ref="son" />
Copy the code

Then get:

const currentChildren = this.$refs.son
Copy the code

Basically solved the problem.

2 is not conducive to componentization

Direct access component instance this way, to a certain extent, hampered the development of modular, modular development process, the method is provided to the outside, the method is for internal use, in the absence of in advance to discuss, and component state opaque cases, everything is unknown, so different developers access to the method, the component risk, Provided component methods, whether properties have some internal coupling. The original idea of component development is not to make internal changes outside the component, but rather to make internal changes that inform externally bound method events. On the other hand, if it is inside the child component, it actively passes some information to the parent component, and it is not sure whether the parent component exists.

3 Sibling components Deeply nested components cannot communicate with each other

And props, if brother direct component of communication, through the parent component as a bridge of communication between, and deep communication components, although do not need to step by step as props communications binding, but have a bit, to gradually to the upper or the lower target instance, how to accurately obtain this is a very headache problem, And with each successive layer, the risks and uncertainties increase.

4 Application Scenarios

Direct instance communication, suited to a known, fixed page structure, requires a high degree of transparency between parent and child components, knowing exactly what method properties they have and what they are used for. So this approach is more suitable for page components than some third-party component libraries or common components.

Three dojo.provide inject

If we say provide and inject in Vue, I will first associate with react context. The functions of the two are very similar to some extent. The parent component exposes methods, attributes, or its own instance through provide, while the descendant component, Slot component, or even the slot component of descendant component, inject parent provide to import. Provide for your own use. A classic example of providing and injecting is the el-form and el-form-item element in Elder-UI

Let’s imagine a scenario with the question in mind

<el-form label-width="80px" :model="formData"> <el-form-item label=" name">< el-input V-model =" formdata.name "></el-input> </el-form-item>< el-form-item label=" age">< el-input V-model =" formdata. age"></el-input> </el-form-item></el-form>Copy the code

We can see that el-Form and El-Form-Item do not need to establish any communication operations. How do el-Form and El-Form-Item relate to each other and share state? We read on with questions.

1 Basic Usage

The ordinary way

We use the parent -> child -> grandchild case

The parent component

<template> <div class="father" > <div> child {{sonMes}} {{ grandSonMes }}</div> <son /> </div></template><script>import son from './son'export default { name:'father', Components :{son /* child component */}, provide(){return {father:this}}, Data (){return {grandSonMes: ", /* Information from the child component */ sonMes: "/* Information sent to the child component */}}, GrandSonSay (value){this.grandSonMes = value}, SonSay (value){this.sonMes = value},},}</script>Copy the code

Here we expose ourselves by providing. ⚠️⚠️⚠️ The name declared here must be the same as the name imported by the child component

Child components

<template> <div class="son" > <input V-model ="mes" /> </template><script>import grandSon from './grandSon'export default {/* name:'son', {grandSon: / / data(){return {mes:''}}, /* Inject :['father'], methods:{ send(){ this.father.sonSay(this.mes) } }, }</script>Copy the code

Child component inject the parent component instance, then can directly get the parent component through this.father, and call sonSay method below.

Sun components

<div class="grandSon" > < grandSon @click="send" > </template><script>export default {/* grandSon */ name:'grandSon', /* Inject :['father'], data(){ return { mes:'' } }, methods:{ send(){ this.father.grandSonSay( this.mes ) } }}</script>Copy the code

The grandson component does not operate, and the method introduced is the same as the child component.

The effect

2 Slot Mode

  • Provide, inject can also be applied to slots, we give the parent component a little change.

    The parent component

  • <template> <div class="father" > <div> child {{sonMes}} {{ grandSonMes }}</div> <son > <grandSon/> </son> </div></template><script>import son from './slotSon'import grandSon From './grandSon' export default {name:'father', components:{grandSon, grandSon, grandSon}, Provide (){return {/ / father:this}}, data(){return {grandSonMes: ", GrandSonSay (value){this.grandSonMes = value}, SonSay (value){this.sonMes = value},},}</script>Copy the code

Child components

<template> <div class="son" > <input v-model="mes" /> < button@click ="send" >Copy the code

The same communication effect was achieved. In fact, the slot mode is located in the component registered by the parent component, and finally the child component is bound under the children of the child component. Pretty much the same thing.

Provied other uses

provideWe can expose not only the entire parent component, but also only a part of it (some properties of the parent component or methods of the parent component) as needed. In the example above, only the parent method is used in the descendant component, so we can provide only two communication methods. But the thing to notice here is that if we’re providing a method, if there’s an operation inside the methodthisBehavior needs to be boundthis

The parent component

Dojo.provide () {return {/ * will communication method the children exposed to the component (note that bind this * / grandSonSay: enclosing grandSonSay. Bind (this), SonSay: this.sonsay.bind (this)}}, methods:{/* grandSonSay(value){this.grandsonmes = value}, SonSay (value){this.sonMes = value},},Copy the code

Child components

Inject :['sonSay'], methods:{send(){this.sonsay (this.mes)}},Copy the code

2 advantages

Component communication is not affected by the sub-component level

Provide inject similar to react. Context.Provide is equivalent to context. Provider and inject is equivalent to context. Consumer to keep parent components from communicating with their underlying descendants.

2 for slots, nested slots

Provide inject makes it easy for slot-nested parent-child components to communicate, which is why el-Forms and El-Form-Items coordinate and manage form state. In element’s source code, el-form provides this itself.

Three shortcomings

1 not suitable for brother communication

Provide – Inject coordination is to obtain the states, methods, properties, etc. provided by the parent components. The flow direction is always from parent to child, provide content that cannot be obtained by sibling components, so sibling components cannot communicate in this way.

2 The parent component cannot actively communicate

Provide -inject is more like the father earning money and giving flowers to his son. The son can take the provided conditions from the father, but the father cannot take anything from the son. As the example shows, the parent component knows nothing about the state of the child component. You cannot initiate communication to child components.

4 Application Scenarios

Provide -inject this communication mode is more suitable for deep-seated complex parent-child generation communication. Descendant components can share the state of the parent component. Moreover, it is suitable for the scenarios of slot type such as EL-form el-form-item.

Four vuex

Vuex is the best solution for dealing with complex component communication in VUE. After all, VUE and Vuex came from the same womb. Vuex is also implemented with VUE at the bottom. I believe many of you are familiar with VUex. Let’s start with vuex.

1 Basic Usage

Vuex file

import Vuex from 'vuex'import Vue from 'vue'Vue.use(Vuex)export default new Vuex.Store({    state:{        fatherMes:'',        sonMes:'',        fatherMesAsync:''    },    mutations:{       sayFaher(state,value){           state.fatherMes = value       },       saySon(state,value){           state.sonMes = value       },       sayAsyncFather(state,value){           state.fatherMesAsync = value       }    },    actions:{       asyncSayFather({ commit },payload){           return new Promise((resolve)=>{               setTimeout(()=>{                   resolve(payload)               },2000)           }).then(res=>{               commit('sayAsyncFather',res)           })       }    }})
Copy the code

In the store file, we declare that the three mutations respectively communicate to the parent component saySon, and the parent component communicates to the child component, The synchronous method sayFaher and the asynchronous method sayAsyncFather,actions simulate an asynchronous task asyncSayFather that is executed three seconds later.

main.js

import store from './components/vuex/store'new Vue({  render: h => h(App),  store}).$mount('#app')
Copy the code

The main js into the store

The parent component

<template> <div class="father" > <input v-model="mes" /> < button@click ="send" > </button><br/> <input V-model ="asyncMes" /> <button @click="asyncSend" >< /button><br/> <div> SonMes}}</div> <son /> </div></template><script>import son from './son'export default {/* Parent component */ name:'father', Components: {son, / * subcomponent * /}, the data () {return {mes: ' ', asyncMes: '}}, computed:{ sonMes(){ return this.$store.state.sonMes } }, mounted(){ console.log(this.$store) }, Methods :{* trigger mutations, send(){this. codestore.com MIT ('sayFaher',this.mes)}, /* Trigger actions, */ asyncSend(){this.$store.dispatch('asyncSayFather',this. AsyncMes)}},}</script>Copy the code

The parent component triggers synchronous asynchronous methods to send information to the child component. Use computed to accept state in VUEX.

Child components

<template> <div class="son" > <div> Parent {{fatherMes}} {{fatherMesAsync}} </div> <input v-model="mes" /> < button@click ="send" > </template><script>export default { name:'son', data(){ return { mes:'', } }, Computed :{/* Accept synchronized messages from the parent component */ fatherMes(){return this.$store.state.fatherMes}, / * accept the parent component asynchronous messaging * / fatherMesAsync () {return this. $store. State. FatherMesAsync}}, Methods :{/* Sending messages to parent components */ send(){this. codestore.com MIT ('saySon',this.mes)},},}</script>Copy the code

The child component’s methods are the same as the parent component’s.

The effect

2 advantages

Fundamentally solve the communication problems of complex components

Vuex solves the complexity of vUE component communication to a certain extent. We no longer care about the communication of two unrelated components.

2 Supports asynchronous component communication

In VUEX, actions allows us to perform some asynchronous operations, and then pass the data to the corresponding mutation via commit. The reason why actions can perform asynchronous operations is that the underlying Promise. Resolve can obtain the status of the completion of the asynchronous task.

Three shortcomings

1 The process is slightly more complicated

Vuex communication is more complex than other modes, and independent modules need to be established for different modules.

4 Application Scenarios

In actual development scenarios, there is no simple communication such as demo project. The emergence of VUEX is to solve these relatively complex component communication scenarios. For medium to large projects, VUEX is a good solution for state management and data communication.

EventBus – EventBus

EventBus event bus, EventBus all events unified scheduling, a unified management event center, a component binding event, another component to trigger events, all the components of communication will no longer receive the limitation of father and son components, the page needs data, binding event, and then the corresponding event is triggered by the data provider to provide the data, This communication scenario applies not only to VUE, but also to React.

This is the same as this.$emit and this.$on in vue. Let’s focus on this process.

1 Basic Usage

EventBus

Export Default class EventBus {es = {} /* Bind event */ on(eventName, cb) {if (! This. Es [eventName]) {this.es[eventName] = []} this.es[eventName].push({cb})} /* Emit (eventName,... params) { const listeners = this.es[eventName] || [] let l = listeners.length for (let i = 0; i < l; i++) { const { cb } = listeners[i] cb.apply(this, params) } }}export default new EventBus()Copy the code

This is a simple event bus with both on and EMIT methods.

The parent component

<template> <div class="father" > <input v-model="mes" /> <button @click="send" > {{ sonMes }}</div> <son /> <brotherSon /> </div></template><script>import son from './son'import brotherSon from './brother'import EventBus from './ EventBus 'export default {name:'father', components:{son,/* child component */ brotherSon, / * subcomponent * /}, the data () {return {mes: ' ', sonMes: "' / * send subcomponents information * /}}, / / eventBus. on('sonSay', this.sonsay)}, Methods :{/* Pass to child components */ send(){eventbus.emit ('fatherSay',this.mes)}, SonSay (value){this.sonMes = value},},}</script>Copy the code

The sonSay method is bound to the sonSay method in EventBus during initialization. When sending information to the child component, the emit triggers the binding method of the child component to realize parent-child communication. Next we look at the components.

Child components

<template> <div class="son" > <div> Parent component says to me: {{fatherMes}} </div> <input v-model="mes" /> <button @click="send" > </button> <div> <input v-model="brotherMes" </button> </div> </template><script>import EventBus from './ EventBus' export default { name:'son', data(){ return { mes:'', brotherMes:'', fatherMes:'' } }, Mounted (){/* EventBus. On ('fatherSay', this.fathersay)}, Methods :{/* Send (){eventbus.emit ('sonSay',this.mes)}, SendBrother (){EventBus. Emit ('brotherSay', this.brothermes)}, FatherSay (value){this.fatherMes = value},}</script>Copy the code

Similar to the logic of the parent component, the method that needs to receive data is bound to the EventBus, and the EventBus method is triggered to pass information to the outside world. We also simulated brothers communicating with each other. We create a sibling component.

<template> <div class="son" > The sibling component says to me: {{ brotherMes }} </div></template><script>import EventBus from './eventBus'export default { /* */ name:'brother', Data (){return {brotherMes:''}}, mounted(){/* Bind event to brotherbus. on('brotherSay', this.brothersay)}, methods:{ brotherSay(value){ this.brotherMes = value } }}</script>Copy the code

As we can see, there is no difference between sibling processing logic and parent processing logic.

The effect

2 advantages

  • 1 simple and flexible, father-son brother communication is not restricted.

    The communication method of eventBus is simpler than the previous ones and is not affected by the component level. It can communicate with any two components. When data is needed, it goes through the ON binding, and when data is sent, it emit.

    2 The communication mode is not affected by the framework

    Not only vUE can use eventBus, React and small programs can use this communication mode, and I think this kind of communication mode is more suitable for small program communication, as for why it will be explained later.

    4 faults

    1 Difficult maintenance, easy to cause chain problems

    If we use this communication mode of event bus, because all events are highly centralized and unified management, if there is a mistake in the middle, it will cause a disaster. And late maintenance is also very difficult.

    2 Requires careful command specification

    The actual application scenario is much more complex than the demo scenario. In the actual scenario, there are countless pairs of parent and child components and countless pairs of brother components. We cannot call each event with the same name, so the name of the eventBus bound event must be strictly regulated.

    3 is not conducive to componentized development

    The eventBus communication approach does not allow for effective componentization. Imagine a scenario where there are multiple common components on a page and we only need to pass data to one of them, but each common component is bound to a method for receiving data. How do we get the data to the required components?

    4 Application Scenarios

Realize the bus is more suitable for this way, WeChat small program, and based on the vue build a small program, as to why, because we all know that small program with double thread model (rendering + logic layer) (as shown in the figure below), rendering layer effect WXML rendering is a small program to our line of sight, and the logic layer is we write code logic, on the performance, The performance wasted in the rendering layer is much larger than the performance overhead in the logical layer. If we pass the props in the applet, the properties are bound to the applet tags, so we have to re-render the view layer. If the page structure is complex, it may cause problems such as lag, so eventBus can bypass the rendering layer and directly have the logical layer to push the data, saving the cost of performance.

Six event bus two New Vue

The communication mode of New Vue is similar to that of eventBus, but the difference is that with the Vue instance as the center of eventBus, we can not only use $ON and $emit, but also use data,watch and other methods under Vue. In addition, we can establish multiple VUES. As a data communication bridge between different modules, new Vue is more efficient and suitable for Vue project scenarios compared with the EventBus method above. Let’s move on.

1 Basic Usage

VueBus

import Vue from 'vue'export default new Vue()
Copy the code

The parent component

<template> <div class="father" > <input v-model="mes" /> <button @click="send" > {{ sonMes }}</div> <son /> </div></template><script>import son from './son'import VueBus from './vueBus'export default { / * * / parent component name: 'father, components: * /} {son, / * child components, data () {return {mes:' ', sonMes: "' / * send subcomponents information * /}}, VueBus._data.mes = 'hello,world'}, mounted(){VueBus.$on('sonSay', this.sonsay)}, VueBus.$emit('fatherSay',this.mes)}, SonSay (value){this.sonMes = value},},}</script>Copy the code

We bind the method that receives the data with $on and bind the data under vue_data at initialization.

Child components

<template> <div class="son" > <div> Parent component says to me: </div> <input v-model="mes" /> <button @click="send" >< /button><br/> <button @click="getFatherMes" </button> </div> </template><script>import VueBus from './ VueBus' export default {name:'son', data(){ return { mes:'', brotherMes:'', fatherMes:'' } }, VueBus.$on('fatherSay', this.fathersay)}, Methods :{VueBus.$emit('sonSay',this.mes)}, FatherSay (value){this.fatherMes = value}, */ getFatherMes(){console.log(vuebus._data.mes)}},}</script>Copy the code

As with the eventBus, we can also get the content passed by the parent component directly from the _data data.

2 advantages

1 Simple and flexible, communication between any components.

Like the eventBus communication method above, this communication method is flexible and can easily be implemented between any component.

2 In addition to communication, watch, computed and other methods can be used

If we use vUE as a communication medium, using only $EMIT and $ON is really overkill. Now that we have a VUE instance, we can easily use vue’s $watch computed and so on.

Three shortcomings

Basically, the shortcomings of EventBus exist in vUE.

4 Application Scenarios

In small and medium sized projects that do not consider vuEX, we can consider using the VUE event bus as a communication method. When using this method, we must pay attention to the namespace and do not bind event names repeatedly. Distinguish service modules to avoid subsequent maintenance difficulties.

Write in the back

When we write the VUE project, we need to make a comprehensive assessment of the specific business scenario, project size and other factors to determine the specific communication mode. This article introduces the advantages and disadvantages of VUE communication, which can provide a reference for practical work.