Lightning Web Componentsで取引先の検索画面を作ってみた

Posted by

概要

Lightning Web Componentを使って何か実装してみたかったので、取引先を検索して一覧を表示する画面を作ってみました。
とりあえず検索条件を入力して結果の一覧を表示するだけものなので、そのままは使えないかもですがもう少しカスタマイズすれば使えるものになるかなと思います。
本記事は、その実装の中で気づいたことを簡単にまとめた内容となります。

デモ

demo

ソースコード
https://github.com/yhayashi30/lwc-account-search

実装で気づいた点

デザイン(html)の作成

デザインについては、Auraの時と同様に専用のタグを使う、もしくは通常のhtmlタグとSLDS(または自前のCSS)の組み合わせで作成する感じです。Auraのタグは<Lightning:XX..>(コロン区切り)だったのに対して、LWCでは<Lightning-XX-..>(ハイフン区切り)のものを使っていく感じです。
<Lightning-XX-..>の部品は、下記のドキュメントにサンプルイメージと、実装が整理されているので参考にしながら作成すると便利です。
<参考>
https://developer.salesforce.com/docs/component-library/overview/components

Apex呼び出し

LWCではApexの呼び出しには、以下の3つの方法があるようです。
– Wire a property
– Wire a function
– Call a method imperatively

Wire Service(Wire a property/Wire a function)

https://developer.salesforce.com/docs/component-library/documentation/lwc/lwc.data_wire_service_about

The wire service provisions an immutable stream of data to the component. Each value in the stream is a newer version of the value that precedes it.

We call the wire service reactive in part because it supports reactive variables, which are prefixed with $. If a reactive variable changes, the wire service provisions new data. We say “provisions” instead of “requests” or “fetches” because if the data exists in the client cache, a network request may not be involved.

<日本語>

Wire Serviceは、reactiveな変数を使用してコンポーネントへのデータの不変なストリームをprovisionできます。ストリーム内の各値は、その前にある値の新しいバージョンです。

Wire Serviceをreactiveと呼んでいます。これは、接頭辞$が付いたreactive変数をサポートしているためです。 reactive変数が変更された場合、Wire Serviceは新しいデータをprovisionします。 データがクライアントキャッシュに存在する場合、ネットワーク要求が関係していない可能性があるため、「request」または「fetch」ではなく「provision」と言います。

とのことで、少数のデータ取得には向いてそうな感じです。
Tipには、下記の記載がありました。

The wire service delegates control flow to the Lightning Web Components engine. Delegating control is great for read operations, but it isn’t great for create, update, and delete operations. As a developer, you want complete control over operations that change data. That’s why you perform create, update, and delete operations with a JavaScript API instead of with the wire service.

<日本語>

Wire Serviceは、Lightning Web Componentエンジンに制御フローを委任します。 委任制御は読み取り操作には適していますが、作成、更新、削除の操作には適していません。 開発者としては、データを変更する操作を完全に制御する必要がある場合は、Wire ServiceではなくJavaScript APIを使用して作成、更新、削除の操作を実行するのはそのためです。

検索→一覧は、データの取得なのでWire Serviceも使えそうでしたが、今回はベーシックな通常のApex呼び出しを使用することにしました。次回は、Wireを使って実装して検証してみたいです。

Call an Apex Method Imperatively

サンプルを見た方が早いと思うので、JsとApex、Htmlは以下のような感じです。
Jsでは、Apexをメソッド単位でimportして呼び出すだけです。
Apexでは、@AuraEnabledを対象のメソッドにつける感じです。(Auraコンポーネントで使用するApexは共有できそうです。)

apexImperativeMethod.js
import { LightningElement, track } from 'lwc';
import getContactList from '@salesforce/apex/ContactController.getContactList';

export default class ApexImperativeMethod extends LightningElement {
    @track contacts;
    @track error;

    handleLoad() {
        getContactList()
            .then(result => {
                this.contacts = result;
            })
            .catch(error => {
                this.error = error;
            });
    }
}
ContactController.cls
public with sharing class ContactController {
    @AuraEnabled(cacheable=true)
    public static List<Contact> getContactList() {
        return [SELECT Id, Name, Title, Phone, Email, Picture__c FROM Contact WHERE Picture__c != null LIMIT 10];
    }
}
apexImperativeMethod.html
<template>
    <lightning-card title="ApexImperativeMethod" icon-name="custom:custom63">
        <div class="slds-m-around_medium">
            <p class="slds-m-bottom_small">
                <lightning-button label="Load Contacts" onclick={handleLoad}></lightning-button>
            </p>
            <template if:true={contacts}>
                <template for:each={contacts} for:item="contact">
                    <p key={contact.Id}>{contact.Name}</p>
                </template>
            </template>
            <template if:true={error}>
                <c-error-panel errors={error}></c-error-panel>
            </template>
        </div>
    </lightning-card>
</template>

コンポーネント間のデータの受け渡し

検索と一覧でコンポーネントを分割して実装したかったのですが、下記の通りAuraのApplication Eventと同じように実現することは可能でした。

To communicate between components that aren’t in the same DOM tree, use a singleton library that follows the publish-subscribe pattern.

In a publish-subscribe pattern, one component publishes an event. Other components subscribe to receive and handle the event. Every component that subscribes to the event receives the event. For example, if you add two components to a Lightning page in Lightning App Builder, use the pubsub module to send events between them.

<日本語>

同じDOMツリーにないコンポーネント間で通信するには、パブリッシュ-サブスクライブパターンに従ったシングルトンライブラリを使用します。

パブリッシュ-サブスクライブパターンでは、1つのコンポーネントがイベントをパブリッシュします。他のコンポーネントはイベントを受信して​​処理するようにサブスクライブします。イベントをサブスクライブするすべてのコンポーネントがイベントを受け取ります。たとえば、Lightning App BuilderのLightningページに2つのコンポーネントを追加する場合は、pubsubモジュールを使用してそれらの間でイベントを送信します。

細かい実装は、下記のサンプルコードを参考にすることで問題なく実装できました。
https://github.com/trailheadapps/lwc-recipes/tree/master/force-app/main/default/lwc/pubsubSearchBar
https://github.com/trailheadapps/lwc-recipes/tree/master/force-app/main/default/lwc/pubsub
https://github.com/trailheadapps/lwc-recipes/tree/master/force-app/main/default/lwc/pubsubContactList

最後に

時間があれば、追加の機能も実装していこうと考えていますので、よかったらGithubもチェックしてみてください。
https://github.com/yhayashi30/lwc-account-search