Vue.js component communication is achieved through several methods, each suited to specific use cases. Below is a comprehensive overview of these methods, including code examples and their characteristics.
Props
- Direction: Parent to Child
- Purpose: Allows a parent component to pass data to a child component via attributes.
-
Characteristics:
- Read-Only: Props are immutable by default in the child component.
- Validation: Props can have defined validation rules.
- Dynamic: Props can update with changes in the parent component’s state.
Parent Component (Parent.vue)
<template>
<div>
<ChildComponent :message="parentMessage" />
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
parentMessage: 'Hello from Parent'
};
}
};
</script>
Child Component (ChildComponent.vue)
<template>
<div>
<p>{{ message }}</p>
</div>
</template>
<script>
export default {
props: {
message: String
}
};
</script>
$emit (Events)
- Direction: Child to Parent
- Purpose: Enables a child component to notify the parent by triggering custom events.
-
Characteristics:
- Data Transmission: Events can carry data payloads.
- Multiple Events: A child can emit multiple distinct events.
Child Component (ChildComponent.vue)
<template>
<button @click="notifyParent">Notify Parent</button>
</template>
<script>
export default {
methods: {
notifyParent() {
this.$emit('child-event', 'Hello from Child');
}
}
};
</script>
Parent Component (Parent.vue)
<template>
<ChildComponent @child-event="handleChildEvent" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
methods: {
handleChildEvent(data) {
console.log('Received data from child:', data);
}
}
};
</script>
Vuex
- Global State Management
- Purpose: Manages application-wide state accessible by any component.
-
Characteristics:
- State: Stores global state data.
- Mutations: Synchronous operations, the only way to modify state.
- Actions: Handle asynchronous operations, dispatching mutations.
- Getters: Computed properties based on state, cached for efficiency.
- Modules: Split state management into modules for large applications.
Setting Up Vuex Store (store.js)
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
sharedCounter: 0
},
mutations: {
increment(state) {
state.sharedCounter++;
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment');
}, 1000);
}
},
getters: {
getCounter: state => state.sharedCounter
}
});
Main Application (main.js)
Ensure the application integrates the Vuex Store:
import Vue from 'vue';
import App from './App.vue';
import store from './store';
new Vue({
store,
render: h => h(App)
}).$mount('#app');
Using Vuex in Components (ComponentUsingVuex.vue)
<template>
<div>
<p>Counter: {{ counter }}</p>
<button @click="increment">Increment</button>
<button @click="incrementAsync">Increment Async</button>
</div>
</template>
<script>
export default {
computed: {
counter() {
return this.$store.getters.getCounter;
}
},
methods: {
increment() {
this.$store.commit('increment');
},
incrementAsync() {
this.$store.dispatch('incrementAsync');
}
}
};
</script>
Provide/Inject
- Cross-Level Communication
- Purpose: Allows an ancestor component to provide data that descendants can inject, bypassing intermediate parent-child hierarchies.
-
Characteristics:
- Hierarchy-Independent: Works across multiple levels but may increase code coupling.
- Limited Use: Best suited for library or framework-level data passing, not general component communication.
Ancestor Component (AncestorComponent.vue)
<template>
<div>
<ChildComponent />
</div>
</template>
<script>
export default {
provide() {
return {
ancestorValue: 'Value from Ancestor'
};
}
};
</script>
Descendant Component (DescendantComponent.vue)
<template>
<div>
<p>Value from Ancestor: {{ ancestorValue }}</p>
</div>
</template>
<script>
export default {
inject: ['ancestorValue'],
mounted() {
console.log('Injected value:', this.ancestorValue);
}
};
</script>
Ref and v-model
- Direct Reference
- Purpose: Allows a parent to directly access a child component instance or enable two-way data binding.
-
Characteristics:
- Refs: Used to access child component instances or DOM elements for direct manipulation.
- v-model: Facilitates two-way data binding, commonly used with form elements or custom components.
Parent Component (ParentComponent.vue)
<template>
<ChildComponent ref="childRef" v-model="parentValue" />
<button @click="logChildRef">Log Child Ref</button>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
parentValue: 'Initial Value'
};
},
methods: {
logChildRef() {
console.log(this.$refs.childRef);
}
}
};
</script>
Child Component (ChildComponent.vue)
<template>
<input :value="value" @input="$emit('input', $event.target.value)" />
</template>
<script>
export default {
props: ['value']
};
</script>
Custom Events
- Event-Based Communication
- Purpose: Enables non-standard communication between components via custom events.
-
Characteristics:
- Flexible: Can be triggered and listened to between any components.
- Complex Interactions: Suitable for specific interactions or intricate component communication.
Child Component (ChildComponent.vue)
<template>
<button @click="customEvent">Send Custom Event</button>
</template>
<script>
export default {
methods: {
customEvent() {
this.$emit('custom-event', 'Data to send');
}
}
};
</script>
Parent Component (ParentComponent.vue)
<template>
<ChildComponent @custom-event="handleCustomEvent" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
methods: {
handleCustomEvent(data) {
console.log('Received custom event data:', data);
}
}
};
</script>
Slots
- Content Distribution
- Purpose: Allows a parent component to insert content into specific areas of a child component.
-
Characteristics:
- Default Slot: The default content area in a child component.
- Named Slots: Multiple slots can be defined, with the parent specifying content placement.
- Scoped Slots: The parent can access child component data to customize slot content.
Parent Component (ParentComponent.vue)
<template>
<WrapperComponent>
<h1 slot="header">Custom Header</h1>
<p slot="body">Custom Body Content</p>
</WrapperComponent>
</template>
<script>
import WrapperComponent from './WrapperComponent.vue';
export default {
components: {
WrapperComponent
}
};
</script>
Wrapper Component (WrapperComponent.vue)
<template>
<div>
<slot name="header"></slot>
<div class="content">
<slot name="body"></slot>
</div>
</div>
</template>
Composition API
- New Feature
- Purpose: Introduced in Vue 3, it provides better logic and data organization within components.
-
Characteristics:
-
setup()
Function: Runs at the start of the component lifecycle, accessing props and lifecycle hooks. -
ref
andreactive
: Manage reactive data. -
provide
andinject
: Enhanced implementations for flexible cross-component data passing.
-
Parent Component (ParentComponent.vue)
<template>
<ChildComponent :count="count" @updateCount="updateCount" />
</template>
<script>
import { ref, onMounted } from 'vue';
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
setup() {
const count = ref(0);
function updateCount(newCount) {
count.value = newCount;
}
onMounted(() => {
console.log('Initial count:', count.value);
});
return {
count,
updateCount
};
}
};
</script>
Child Component (ChildComponent.vue)
<template>
<button @click="increment">Increment</button>
</template>
<script>
import { ref } from 'vue';
export default {
props: ['count'],
setup(props, { emit }) {
const count = ref(props.count);
function increment() {
count.value++;
emit('updateCount', count.value);
}
return {
count,
increment
};
}
};
</script>
👉 Click to join and systematically improve development capabilities: Advanced Development Tutorial
Top comments (0)