#Lightning Message Serviceとは
Lightningページ内でDOM全体の通信を行うものです。LWCは複数のコンポーネントを使用してページを構成することが多いですが、その時にコンポーネント間でPub-Sub方式で通信をすることが出来ます。ちなみにLWCだけでなく、VisualforceやAuraコンポーネントでも通信が出来ますが今回はLWC間で通信を行います。
#作成するもの
今回作成するものは取引先をクリックしたら、その取引先の取引先責任者を表示するものです。1画面であればなんてことないものですが、2つのコンポーネントに跨る場合はMessage Serviceが必要になります。
####初期画面
####一番上の取引先をクリック
右のコンポーネントに取引先に紐づく取引先責任者が表示される。
#メッセージチャネルの作成
Lightning Message Serviceを使用するにはLightningMessageChannelメタデータ型を定義する必要があるそうです。force-app/main/defaultにmessageChannelsディレクトリを作成し、xmlファイルを作成します。
<?xml version="1.0" encoding="UTF-8"?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
<description>This is a sample Lightning Message Channel for the Lightning Web Components.</description>
<isExposed>true</isExposed>
<lightningMessageFields>
<description>This is the record Id that changed</description>
<fieldName>recordId</fieldName>
</lightningMessageFields>
<masterLabel>SampleMessageChannel</masterLabel>
</LightningMessageChannel>
masterLabelに任意の名前を入力します。
#取引先のリスト
まずは左側のコンポーネントです。こちらはメッセージを公開する側です。
<template>
<lightning-card title="Account List" icon-name="custom:custom1">
<div class="slds-m-around_medium" onaccountselect={handleAccountSelect}>
<template if:true={account.data}>
<template for:each={account.data} for:item="acc">
<c-account-list-item key={acc.Id} account={acc}></c-account-list-item>
</template>
</template>
</div>
</lightning-card>
</template>
import { LightningElement, wire } from 'lwc';
import getAccountList from '@salesforce/apex/AccountTableViewController.getAccountList';
import { publish, MessageContext } from 'lightning/messageService';
import SampleMC from '@salesforce/messageChannel/SampleMessageChannel__c';
export default class AccountList extends LightningElement {
@wire(getAccountList)
account;
@wire(MessageContext)
messageContext;
handleAccountSelect(event) {
console.log('select');
const payload = { recordId: event.target.account.Id };
publish(
this.messageContext,
SampleMC,
payload
)
}
}
下記の2行でpublishとMessageContextと、先ほど作成したメタデータをimportします。作成したメタデータファイル名の最後に「__c」をつけないといけないらしいです。
import { publish, MessageContext } from 'lightning/messageService';
import SampleMC from '@salesforce/messageChannel/SampleMessageChannel__c';
@wire(MessageContext)でMessageContextオブジェクトを作成します。payloadが今回右側のコンポーネントに渡す取引先のIdになります。ここは形式を覚えておけば大丈夫です。
#取引先責任者のリスト
こちらはメッセージを受け取る側のコンポーネントです。
import { LightningElement, wire } from 'lwc';
import getContacts from '@salesforce/apex/ContactHandler.getContacts';
import { subscribe, unsubscribe, APPLICATION_SCOPE, MessageContext } from 'lightning/messageService';
import SampleMC from '@salesforce/messageChannel/SampleMessageChannel__c';
export default class ContactDetail extends LightningElement {
subscription = null;
recordId;
@wire(getContacts, {accId : '$recordId'})
contacts;
@wire(MessageContext)
messageContext;
// messageを購読
subscribeToMessageChannel() {
if(!this.subscription) {
this.subscription = subscribe(
this.messageContext,
SampleMC,
(message) => this.recordId = message.recordId,
{scope: APPLICATION_SCOPE}
);
}
}
unsubscribeToMessageChannel() {
unsubscribe(this.subscription);
this.subscription = null;
}
connectedCallback() {
this.subscribeToMessageChannel();
}
disconnectedCallback() {
this.unsubscribeToMessageChannel();
}
}
受け取る側では下記2行をインポートします。
import { subscribe, unsubscribe, APPLICATION_SCOPE, MessageContext } from 'lightning/messageService';
import SampleMC from '@salesforce/messageChannel/SampleMessageChannel__c';
connectedCallbackでsubscribeToMessageChannelを呼び出し、メッセージを購読します。今回の場合はrecordIdですのでmessage.recordIdをthis.recordIdに代入します。あとは@wireを使用して取引先責任者のレコードを取得して表示するだけです。
Pub-Sub方式になじみがなかったのではじめは戸惑いましたが、メッセージのやり取りのイメージさえ掴めればそこまで難しくないです。どの程度使用する機会があるか分かりませんが、使い道はある気がします。