イベントの作成とディスパッチ

コンポーネントの JavaScript クラスでイベントを作成してディスパッチします。イベントを作成するには、CustomEvent() コンストラクタを使用します。イベントをディスパッチするには、EventTarget.dispatchEvent() メソッドをコールします。

CustomEvent() コンストラクタでは、イベント種別を示す文字列のみが必須のパラメータとなります。コンポーネントの作成者は、イベントを作成するときにイベント種別を指定します。イベント種別としては任意の文字列を使用できます。ただし、DOM イベントの標準に準拠することをお勧めします。

  • すべて小文字
  • スペースなし
  • 単語と単語の区切りはアンダースコア

インラインイベントハンドラ名の先頭は on でなければならないため、イベント名の先頭には on を付けないでください。イベント名が onmessage の場合、マークアップは <c-my-component ononmessage={handleMessage}> になります。onon と言葉が重複しているため、混乱の原因となります。

カスタムイベントによるコンポーネント間通信

では、コードを確認しましょう。

c-paginator コンポーネントには、[前へ] ボタンと [次へ] ボタンがあります。ユーザがこれらのボタンをクリックすると、コンポーネントはそれぞれ previous イベントと next イベントを作成してディスパッチします。paginator コンポーネントは、[前へ] ボタンと [次へ] ボタンが必要な任意のコンポーネントにドロップできます。その親コンポーネントはイベントをリスンして処理します。

1<!-- paginator.html -->
2<template>
3  <lightning-layout>
4    <lightning-layout-item>
5      <lightning-button
6        label="Previous"
7        icon-name="utility:chevronleft"
8        onclick={previousHandler}
9      ></lightning-button>
10    </lightning-layout-item>
11    <lightning-layout-item flexibility="grow"></lightning-layout-item>
12    <lightning-layout-item>
13      <lightning-button
14        label="Next"
15        icon-name="utility:chevronright"
16        icon-position="right"
17        onclick={nextHandler}
18      ></lightning-button>
19    </lightning-layout-item>
20  </lightning-layout>
21</template>

ユーザがボタンをクリックすると、previousHandler または nextHandler 関数が実行されます。これらの関数は previous イベントと next イベントを作成してディスパッチします。

1// paginator.js
2import { LightningElement } from "lwc";
3
4export default class Paginator extends LightningElement {
5  previousHandler() {
6    this.dispatchEvent(new CustomEvent("previous"));
7  }
8
9  nextHandler() {
10    this.dispatchEvent(new CustomEvent("next"));
11  }
12}

これらは単に「何かが起きた」ことだけを通知するイベントです。DOM ツリーで上方向にデータペイロードを渡すことはせず、単にユーザがボタンをクリックしたことのみを通知します。

previous イベントと next イベントをリスンして処理する c-event-simple というコンポーネントに paginator をドロップしてみましょう。

イベントをリスンするには、oneventtype という構文で HTML 属性を使用します。イベント種別は previousnext であるため、リスナーは onpreviousonnext になります。

1<!-- eventSimple.html -->
2<template>
3  <lightning-card title="EventSimple" icon-name="custom:custom9">
4    <div class="slds-m-around_medium">
5      <p class="slds-m-vertical_medium content">Page {page}</p>
6      <c-paginator onprevious={previousHandler} onnext={nextHandler}></c-paginator>
7    </div>
8  </lightning-card>
9</template>

c-event-simpleprevious イベントまたは next イベントを受け取ると、previousHandler 関数または nextHandler 関数が実行されて、ページ番号が 1 つ減り/増えます。

1// eventSimple.js
2import { LightningElement } from "lwc";
3
4export default class EventSimple extends LightningElement {
5  page = 1;
6
7  previousHandler() {
8    if (this.page > 1) {
9      this.page = this.page - 1;
10    }
11  }
12
13  nextHandler() {
14    this.page = this.page + 1;
15  }
16}

github.com/trailheadapps/lwc-recipes リポジトリの c-event-simple コンポーネントc-paginator コンポーネントをチェックアウトしてください。

Tip

イベントでのデータの受け渡し 

受信側のコンポーネントまでデータを渡すには、CustomEvent コンストラクタで detail プロパティを設定します。受信側のコンポーネントは、イベントリスナーのハンドラ関数で detail プロパティのデータにアクセスします。

CustomEvent インターフェースには、detail プロパティの型や構造の要件はありません。ただし、プリミティブ型のデータのみを送信することが重要です。JavaScript は、プリミティブ型以外のすべてのデータ型を参照によって渡します。コンポーネントの detail プロパティにオブジェクトが含まれていると、どのリスナーであってもコンポーネントについての知識なしでそのオブジェクトを変更できてしまいます。これは重大な問題です。プリミティブのみを送信するか、またはデータを detail プロパティに追加する前に新しいオブジェクトにコピーすることがベストプラクティスです。新しいオブジェクトにデータをコピーすることで、必要なデータのみが送信されること、そして受信側でデータを変更できなくなることを保証できます。

Note

lwc-recipes リポジトリの c-event-with-data コンポーネントを見てみましょう。

選択された取引先責任者の名前、役職、電話番号、メールアドレスが表示されている取引先責任者のリスト。

取引先責任者リストの各項目は、ネストされた c-contact-list-item コンポーネントです。

c-contact-list-item コンポーネントは、selectHandler 関数を実行する onclick イベントリスナーで取引先責任者の名前と写真をアンカータグにラップします。

1<!-- contactListItem.html -->
2<template>
3    <a href="#" onclick={selectHandler}>
4        <lightning-layout vertical-align="center">
5            <lightning-layout-item>
6                <img src={contact.Picture__c}></img>
7            </lightning-layout-item>
8            <lightning-layout-item padding="around-small">
9                <p>{contact.Name}</p>
10            </lightning-layout-item>
11        </lightning-layout>
12    </a>
13</template>

ユーザが取引先責任者をクリックして選択すると、コンポーネントは selected という CustomEvent を作成してディスパッチします。イベントには、選択された取引先責任者の ID である detail: this.contact.Id というデータが含まれます。親コンポーネントの c-event-custom は、取引先責任者の参照を使用して、取引先責任者の詳細を表示します。

1// contactListItem.js
2import { LightningElement, api } from "lwc";
3
4export default class ContactListItem extends LightningElement {
5  @api contact;
6
7  selectHandler(event) {
8    // Prevents the anchor element from navigating to a URL.
9    event.preventDefault();
10
11    // Creates the event with the contact ID data.
12    const selectedEvent = new CustomEvent("selected", { detail: this.contact.Id });
13
14    // Dispatches the event.
15    this.dispatchEvent(selectedEvent);
16  }
17}

c-event-with-data コンポーネントは、onselected 属性で selected イベントをリスンして、contactSelected イベントハンドラで処理します。

1<!-- eventWithData.html -->
2<template>
3    <lightning-card title="EventWithData" icon-name="custom:custom9">
4        <lightning-layout class="slds-m-around_medium">
5            <lightning-layout-item>
6                <template lwc:if={listIsNotEmpty}>
7                    <template for:each={contacts.data} for:item="contact">
8                        <c-contact-list-item key={contact.Id} contact={contact} onselected={contactSelected}></c-contact-list-item>
9                    </template>
10                </template>
11            </lightning-layout-item>
12            <lightning-layout-item class="slds-m-left_medium">
13                <template lwc:if={selectedContact}>
14                    <img src={selectedContact.Picture__c}></img>
15                    <p>{selectedContact.Name}</p>
16                    <p>{selectedContact.Title}</p>
17                    <p><lightning-formatted-phone value={selectedContact.Phone}></lightning-formatted-phone></p>
18                    <p><lightning-formatted-email value={selectedContact.Email}></lightning-formatted-email></p>
19                </template>
20            </lightning-layout-item>
21        </lightning-layout>
22    </lightning-card>
23</template>

contactSelected イベントハンドラでは、コンポーネントは event.detail プロパティを contactId プロパティに割り当てます。そして、その ID を持つ取引先責任者を、@wire でプロビジョニングされた contacts 配列で探し、取引先責任者の名前、役職、電話番号、メールアドレスをテンプレートに表示します。

1// eventWithData.js
2import { LightningElement, wire } from "lwc";
3import getContactList from "@salesforce/apex/ContactController.getContactList";
4
5export default class EventWithData extends LightningElement {
6  selectedContact;
7
8  @wire(getContactList) contacts;
9
10  contactSelected(event) {
11    const contactId = event.detail;
12    this.selectedContact = this.contacts.data.find((contact) => contact.Id === contactId);
13  }
14
15  get listIsNotEmpty() {
16    return this.contacts && Array.isArray(this.contacts.data) && this.contacts.data.length > 0;
17  }
18}

github.com/trailheadapps/lwc-recipes リポジトリの c-event-with-data コンポーネントをチェックアウトしてください。

Tip

関連トピック

The Japanese Summer '24 guide is now live

日本語の Summer '24 ガイドが公開されました! 「Component Reference (コンポーネントリファレンス)」は、以前と同様にコンポーネントライブラリにあります。