Introduction
Communication between components is crucial to creating responsive and dynamic applications. There are different ways to communicate between Lightning Web Components (LWC), depending on the relationship between the components or event being communicated. For each method, we'll look at a really simple example, focusing on information that only applies to that specific method. By the end of this article, you will have a better understanding of how to communicate between LWC.
What are the ways to communicate between components in LWC?
There are 3 ways to communicate between components in LWC:
- Parent-to-Child communication is used when the Parent component's HTML file includes a Child component and we need to pass data from the Parent component to the Child component or call a function in the Child component.
- Child-to-Parent communication is used when we need to pass data from the Child component to the Parent component.
- Communication between unrelated components is used to exchange data between components that don’t have a common parent component.
-
Parent-to-Child communication
To enable Parent-to-Child communication, the child component must have a public property or function declared using the @api decorator.
Pass data to a Child property
child.js
import { LightningElement, api } from 'lwc';
export default class Child extends LightningElement {
@api childVar;
}
child.html
<template>
</template>
parent.html
<template>
<c-child child-var={parentVar}></c-child>
</template>
parent.js
import { LightningElement } from 'lwc';
export default class Parent extends LightningElement {
parentVar = 'Hello!';
}
Call a Child function
To call a child function, it is necessary to take into account that this can only be done after the child's component has entered the DOM. So in this example I am using the renderedCallback method.
child.js
import { LightningElement, api } from 'lwc';
export default class Child extends LightningElement {
@api
childFunction() {
return 'Hello!';
}
}
child.html
<template>
</template>
parent.js
import { LightningElement } from 'lwc';
export default class Parent extends LightningElement {
renderedCallback() {
let childCmp = this.template.querySelector('c-child');
let result = childCmp.childFunction();
}
}
parent.html
<template>
<c-child></c-child>
</template>
2. Child-to-Parent communication
The Child component cannot directly pass data to the Parent component using property, so this can be done by dispatching a custom event from the Child component, and the Parent component must listen for this event.
Child-to-Parent
child.js
import { LightningElement } from 'lwc';
export default class Child extends LightningElement {
renderedCallback() {
this.childFunction();
}
childFunction() {
this.dispatchEvent(new CustomEvent('childevent', {
detail: {
childVar: 'Hello!',
}
}));
}
}
child.html
<template>
</template>
parent.js
import { LightningElement } from 'lwc';
export default class Parent extends LightningElement {
parentFunction(event) {
let result = event.detail.childVar;
}
}
parent.html
<template>
<c-child onchildevent={parentFunction}></c-child>
</template>
Child-to-Grandparent
When we have a chain of nested components, we often need to pass data from a child component to the grandparent component. So we need to configure Event Propagation using the bubbles property set to true in dispatchEvent on the intermediate components (in our case, it is the Parent component).
child.js
import { LightningElement } from 'lwc';
export default class Child extends LightningElement {
renderedCallback() {
this.childFunction();
}
childFunction() {
this.dispatchEvent(new CustomEvent('childevent', {
detail: {
childVar: 'Hello!',
}
}));
}
}
child.html
<template>
</template>
parent.js
import { LightningElement } from 'lwc';
export default class Parent extends LightningElement {
parentFunction(event) {
this.dispatchEvent(new CustomEvent('parentevent', {
bubbles: true,
detail: event.detail
}));
}
}
parent.html
<template>
<c-child onchildevent={parentFunction}></c-child>
</template>
grandparent.js
import { LightningElement } from 'lwc';
export default class Grandparent extends LightningElement {
grandparentFunction(event) {
let result = event.detail.childVar;
}
}
grandparent.html
<template>
<c-parent onparentevent={grandparentFunction}></c-parent>
</template>
3. Communication between unrelated components
To communicate between unrelated components Lightning Message Service (LMS) should be used. LMS is a publish and subscribe (pub-sub) service.
First of all, create a Message Channel. To do this, create a messageChannels folder in your project in VSCode. In the folder, create MyMessageChannel.messageChannel-meta.xml file with the content below and deploy it to your org.
MyMessageChannel.messageChannel-meta.xml
<?xml version="1.0" encoding="UTF-8" ?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
<masterLabel>MyMessageChannel</masterLabel>
<isExposed>true</isExposed>
<description>Sends messages to unrelated components</description>
<lightningMessageFields>
<fieldName>value</fieldName>
<description>The value to send to a component</description>
</lightningMessageFields>
</LightningMessageChannel>
Then create 2 unrelated components. The first has an input field and publishes value from the field via the Message Channel. The second subscribes to this Message Channel and displays the value.
component1.html
<template>
<lightning-input onchange={sendMessage}></lightning-input>
</template>
component1.js
import { LightningElement, wire } from 'lwc';
import { publish, MessageContext } from 'lightning/messageService';
import MY_MESSAGE_CHANNEL from '@salesforce/messageChannel/MyMessageChannel__c';
export default class Component1 extends LightningElement {
@wire(MessageContext)
messageContext;
sendMessage(event) {
const payload = {
value: event.target.value,
};
publish(this.messageContext, MY_MESSAGE_CHANNEL, payload);
}
}
component2.html
<template>
<p>{value}</p>
</template>
component2.js
import { LightningElement, wire } from 'lwc';
import { subscribe, MessageContext } from 'lightning/messageService';
import MY_MESSAGE_CHANNEL from '@salesforce/messageChannel/MyMessageChannel__c';
export default class Component1 extends LightningElement {
value;
subscription;
@wire(MessageContext)
messageContext;
connectedCallback() {
this.subscribeToMessageChannel();
}
subscribeToMessageChannel() {
this.subscription = subscribe(
this.messageContext,
MY_MESSAGE_CHANNEL,
(message) => this.handleMessage(message)
);
}
handleMessage(message) {
this.value = message.value;
}
}
Conclusion
We've covered Parent-to-Child, Child-to-Parent and unrelated components communications. I hope the examples above have helped you gain a clearer understanding of how to communicate between Lightning Web Components.
If you need any help, don’t hesitate to contact us. Leave a request and we will help you!