Vue Component Communication Techniques
Props and Events (Parent-Child Communication)
Parent components pass data to child components via props, while child components communicate with parents using events.
Parent to Child Data Flow
Props establish one-way data binding from parent to child. When parent data changes, child components automatically update.
// Parent Component
<template>
<div class="parent-container">
<child-component :user-data="userInfo" :action-handler="processAction"></child-component>
</div>
</template>
<script>
import ChildComponent from "./ChildComponent.vue";
export default {
name: "ParentComponent",
data() {
return {
userInfo: "Parent component information"
};
},
methods: {
processAction() {
console.log("Processing action in parent");
}
},
components: {
ChildComponent
}
};
</script>
// Child Component
<template>
<div class="child-container">
<p>{{ userData }}</p>
<button @click="actionHandler">Execute Action</button>
</div>
</template>
<script>
export default {
name: "ChildComponent",
props: ["userData", "actionHandler"]
};
</script>
Child to Parent Communication
Child components emit custom events that parent components listen for using v-on directives.
// Parent Component
<template>
<div class="main-section">
<book-list :books="bookCollection" @item-selected="handleSelection"></book-list>
<p>Selected Index: {{ selectedIndex }}</p>
</div>
</template>
<script>
import BookList from './components/BookList.vue'
export default {
name: 'BookApp',
components: { BookList },
data() {
return {
selectedIndex: -1,
bookCollection: ['Pride and Prejudice', 'Moby Dick', 'Great Expectations']
}
},
methods: {
handleSelection(index) {
this.selectedIndex = index
}
}
}
</script>
// Child Component
<template>
<div>
<div v-for="(book, index) in books" :key="index" @click="selectItem(index)">{{ book }}</div>
</div>
</template>
<script>
export default {
props: ['books'],
methods: {
selectItem(index) {
this.$emit('item-selected', index)
}
}
}
</script>
Event Bus Pattern
Event buses facilitate communication between any components, regardless of their relationship hierarchy.
// Event bus setup
import Vue from 'vue'
export const EventChannel = new Vue()
// Component emitting event
<template>
<div>
<button @click="incrementCounter">Increase Count</button>
</div>
</template>
<script>
import {EventChannel} from './event-channel.js'
export default {
data(){
return{
counter: 0
}
},
methods:{
incrementCounter(){
EventChannel.$emit('counter-increase', {
count: this.counter++
})
}
}
}
</script>
// Component receiving event
<template>
<div>Total Count: {{ total }}</div>
</template>
<script>
import { EventChannel } from './event-channel.js'
export default {
data() {
return {
total: 0
}
},
mounted() {
EventChannel.$on('counter-increase', params => {
this.total = this.total + params.count;
})
}
}
</script>
Dependency Injetcion (Provide/Inject)
This method enables deep component tree communication without explicit prop passing through intermediate components.
// Ancestor component providing data
provide() {
return {
sharedData: this.sharedValue
};
}
// Descendant component receiving data
inject: ['sharedData']
// Alternative approach accessing entire component instance
provide() {
return {
rootComponent: this
};
}
data() {
return {
sharedValue: 'shared information'
};
}
inject: ['rootComponent']
console.log(this.rootComponent.sharedValue)
Component References
Direct component instance access enables method calls and property access between parent and child components.
// Child component definition
export default {
data () {
return {
componentName: 'Vue Component'
}
},
methods: {
showMessage () {
console.log('Component method executed')
}
}
}
// Parent component usage
<template>
<child-comp ref="childReference"></child-comp>
</template>
<script>
import ChildComp from './ChildComp.vue'
export default {
components: { ChildComp },
mounted () {
console.log(this.$refs.childReference.componentName);
this.$refs.childReference.showMessage();
}
}
</script>
Parent and Children Instance Access
Components can directly access their parent or children instances through special Vue properties.
// Child component accessing parent
<template>
<div>
<span>{{ componentMessage }}</span>
<p>Parent value: {{ parentValue }}</p>
</div>
</template>
<script>
export default {
data() {
return {
componentMessage: 'Component data'
}
},
computed:{
parentValue(){
return this.$parent.parentData;
}
}
}
</script>
// Parent component modifying child
<template>
<div class="container">
<div>{{ parentData }}</div>
<child-comp></child-comp>
<button @click="updateChild">Update Child Data</button>
</div>
</template>
<script>
import ChildComp from './ChildComp.vue'
export default {
components: { ChildComp },
data() {
return {
parentData: 'Initial data'
}
},
methods: {
updateChild() {
this.$children[0].componentMessage = 'Updated data'
}
}
}
</script>
Attribute and Listener Inheritance
These features enable cross-component communication by inheriting attributes and event listeners.
// Root component
<template>
<div id="application">
<intermediate-comp :data-prop="firstData" :secondary-prop="secondData" @first-event="handleFirst" @second-event="handleSecond"></intermediate-comp>
</div>
</template>
<script>
import IntermediateComp from './IntermediateComp.vue';
export default {
components: { IntermediateComp },
methods: {
handleFirst() {
console.log('First event handled');
},
handleSecond() {
console.log('Second event handled');
}
}
};
</script>
// Intermediate component
<template>
<div class="middle-component">
<p>Props: {{ dataProp }}</p>
<p>Attributes: {{ $attrs }}</p>
<final-component v-bind="$attrs" v-on="$listeners"></final-component>
</div>
</template>
<script>
import FinalComponent from './FinalComponent.vue';
export default {
props: ['dataProp'],
components: { FinalComponent },
inheritAttrs: false,
mounted() {
this.$emit('first-event');
}
};
</script>
// Final component
<template>
<div class="end-component">
<p>Props: {{ secondaryProp }}</p>
<p>Attributes: {{ $attrs }}</p>
</div>
</template>
<script>
export default {
props: ['secondaryProp'],
inheritAttrs: false,
mounted() {
this.$emit('second-event');
}
};
</script>