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
provide
We 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 methodthis
Behavior 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.