進行状況の追跡を始めよう
Trailhead のホーム
Trailhead のホーム

Lightning Web コンポーネントの作成

学習の目的

この単元を完了すると、次のことができるようになります。

  • 各コンポーネントファイルの内容を説明する。
  • Lightning Web コンポーネントの JavaScript メソッドを作成する。
  • コンポーネント JavaScript でライフサイクルフックを使用する。

Playground で試す

Salesforce の特定のオブジェクトとは関係なく、データ表示要素を作成するとします。ぴったりの例が、ebikes サンプルリポジトリにある productCard component です。そのカードコンポーネントを調べ、独自のバージョンをゼロから作成して、どうすればそれが本格的な Lightning Web コンポーネントに進化するのかを確認しましょう。Lightning Web Components Playground でコンポーネントの各部を構築し、他のサンプルを見て回ることで、すぐに基本を習得できます。

コンポーネントに必要なのは、同じ名前を持つフォルダとファイルのみです。それらは名前と場所で自動的にリンクされます。

フォルダ内のコンポーネントファイル

すべての Lightning Web コンポーネントには名前空間があり、フォルダ名とはハイフンで区切られます。たとえば、デフォルト名前空間 c 内にあるフォルダ名 app の Lightning Web コンポーネントのマークアップは <c-app> です。これは、Lightning Web Components Playground の main.js 内で確認できます。

ただし、Salesforce Platform では、コンポーネントのフォルダ名やファイル名にハイフンの使用は許可されません。では、コンポーネント名が「mycomponent」のように複数の単語でできている場合はどうすればよいでしょうか? フォルダとファイルに my-component という名前を付けることはできませんが、便利な解決策があります。

キャメルケースを使用してコンポーネント名を myComponent にします。キャメルケースのコンポーネントフォルダ名をマークアップのケバブケース (ハイフンで結合された単語) に対応付けます。マークアップでフォルダ名 myComponent のコンポーネントを参照するには、<c-my-component> を使用します。

たとえば、LWC サンプルリポジトリには、viewSource コンポーネントのファイルが含まれる viewSource フォルダがあります。hello コンポーネント が HTML で viewSource コンポーネントを参照するときは、c-view-source を使用します。

HTML ファイルの中身

Lightning Web コンポーネントの HTML ファイルのすべてに、template タグが含まれます。template タグには、コンポーネントの構造を定義する HTML が含まれます。ebikes リポジトリにある productCard コンポーネントの簡易バージョンの HTML を見てみましょう

以下の例を Lightning Web Components Playground に貼り付けていきます。

  1. 新規のプロジェクトを開始するには、[新規] をクリックします。
  2. 次のコードを app.html に貼り付けます (ファイル内の既存の HTML を置き換えます)。
<template>
    <div>
        <div>Name: {name}</div>
        <div>Description: {description}</div>
        <div>Category: {category}</div>
        <div>Material: {material}</div>
        <div>Price: {price}</div>
        <div><img src={pictureUrl}/></div>
    </div>
</template>

中括弧 {} で囲まれた識別子は、対応する JavaScript クラス内の同じ名前の項目にバインドされます。

以下は、この HTML をサポートするための JavaScript ファイルです。これを app.js に貼り付けます。

import { LightningElement } from 'lwc';
export default class App extends LightningElement {
   name = 'Electra X4';
   description = 'A sweet bike built for comfort.';
   category = 'Mountain';
   material = 'Steel';
   price = '$2,700';
   pictureUrl = 'https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax4.jpg';
}

プレビューに自転車と詳細が表示されます。表示されない場合は、[Run (実行)] をクリックします。

たとえば、データを表示するのに、読み込みに少し時間がかかることがわかっているとします。何かあったのかとユーザを心配させたくありません。テンプレート内で if:false および if:true 条件付きディレクティブを使用して、どの視覚要素が表示されているかを判別できます。

"display" div タグ内の次のコンテンツは、HTML ファイルの ready の値が true になるまで表示されません。

<template>
    <div id="waiting" if:false={ready}>Loading…</div>
    <div id="display" if:true={ready}>
        <div>Name: {name}</div>
        <div>Description: {description}</div>
        <div>Category: {category}</div>
        <div>Material: {material}</div>
        <div>Price: {price}</div>
        <div><img src={pictureUrl}/></div>
    </div>
</template>

以下の JavaScript を使用して、Playground でテストします。ここではデータ値が保持され、3 秒のタイマーが設定されます。3 秒後に、コンテンツは表示されるはずです(もちろん、これはテストのみが目的です)。

import { LightningElement } from 'lwc';
export default class App extends LightningElement {
   name = 'Electra X4';
   description = 'A sweet bike built for comfort.';
   category = 'Mountain';
   material = 'Steel';
   price = '$2,700';
   pictureUrl = 'https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax4.jpg';
   ready = false;
   connectedCallback() {
       setTimeout(() => {
           this.ready = true;
       }, 3000);
   }
}

[Run (実行)] をクリックして、条件付きディレクティブの動作を確認します。

基本 Lightning Web コンポーネント

すべてのコンポーネントをゼロから作成したくはないでしょう。そこで、基本 Lightning Web コンポーネントを使用することを検討します。当然、データ型、表示コントローラ、ナビゲーション項目など、多くのコンポーネントがあります。そのすべては、「Component Reference (コンポーネントリファレンス)」にリストされています。

自転車の詳細が目立つようにしましょう。そのためには、最後の例の material と category の div タグを lightning-badge コンポーネントに置き換えます。HTML は次のようになります。

<template>
    <div id="waiting" if:false={ready}>Loading…</div>
    <div id="display" if:true={ready}>
        <div>Name: {name}</div>
        <div>Description: {description}</div>
        <lightning-badge label={material}></lightning-badge>
        <lightning-badge label={category}></lightning-badge>
        <div>Price: {price}</div>
        <div><img src={pictureUrl}/></div>
    </div>
</template>

SteelMountain という語がバッジとして表示されます。非常にシンプルです。

Lightning バッジを使用

よろしいでしょうか。JavaScript を見てみましょう。

JavaScript の処理

ここで実際の処理が行われます。これまで見てきたように、JavaScript メソッドは、入力、データ、イベント、状態への変更などの処理を定義して、コンポーネントを動作させます。

Lightning Web コンポーネントの JavaScript ファイルには、少なくとも次のコードを含める必要があります。MyComponent は、コンポーネントクラスに割り当てる名前になります。

import { LightningElement } from 'lwc';
export default class MyComponent extends LightningElement {
}

export ステートメントで、LightningElement クラスを拡張するクラスを定義します。ベストプラクティスとして、クラスの名前は通常、JavaScript クラスのファイル名と同じにしますが、必須ではありません。

LWC モジュール

Lightning Web コンポーネントでは、モジュール (ECMAScript 6 で組み込みモジュールが導入されました) を使用して、コア機能をバンドルし、コンポーネントファイルの JavaScript がアクセスできるようにします。Lightning Web コンポーネントのコアモジュールは lwc です。

モジュールを import ステートメントで開始し、コンポーネントで使用するモジュールの機能を指定します。

import ステートメントは、JavaScript が lwc モジュールから LightningElement 機能を使用することを示しています。

// import module elements
import { LightningElement} from 'lwc';
// declare class to expose the component
export default class App extends LightningElement {
    ready = false;
    // use lifecycle hook
    connectedCallback() {
        setTimeout(() => {
            this.ready = true;
        }, 3000);
    }
}
  • LightningElement は、Lightning Web コンポーネントの基本クラスで、connectedCallback() を使用できるようにします。
  • connectedCallback() メソッドは、ライフサイクルフックの 1 つです。ライフサイクルフックについては、次のセクションで詳しく説明します。ここでは、ドキュメントオブジェクトモデル (DOM) にコンポーネントが挿入されるとメソッドがトリガーされるということを知っておいてください。この場合は、タイマーが開始されます。

ライフサイクルフック

Lightning Web コンポーネントでは、コンポーネントのライフサイクルで重要なイベントは発生したらコードを「フック」できるようにするメソッドが提供されています。こうしたイベントとして、コンポーネントに次の変化があった場合などが含まれます。

  • 作成
  • DOM に追加された
  • ブラウザで表示された
  • エラーが発生した
  • DOM から削除された

こうしたライフサイクルイベントにコールバックメソッドを使用して対応できます。たとえば、connectedCallback() は、コンポーネントが DOM に挿入されると呼び出されます。disconnectedCallback() は、コンポーネントが DOM から削除されると呼び出されます。

条件付き表示のテストに使用した JavaScript ファイルでは、connectedCallback() を使用して、コンポーネントが DOM に挿入されたらコードが自動的に実行されるようにしました。コードは 3 秒待機してから、readytrue に設定します。

import { LightningElement } from 'lwc';
export default class App extends LightningElement {
    ready = false;
    connectedCallback() {
        setTimeout(() => {
            this.ready = true;
        }, 3000);
    }
}
メモ

メモ

この例を VS Code などのエディタで使用すると、setTimeout() 関数に「Restricted async operation.... (制限された非同期操作....)」という Lint 警告表示されることがあります。この警告は、誤用されることが多い非同期操作を使用していることを示していて、イベントを待つのではなく時間に基づいて動作を遅延します。その場合、setTimeout() は任意の遅延時間を示すのに適しており、警告が表示されても問題なく使用できます。

また、this キーワードが使用されていたことに注目してください。JavaScript を記述したことがあればキーワードの使用に慣れているでしょう。this は、他の環境と同じに動作します。JavaScript のこの this キーワードは、現在のコンテキストの最上位を示します。ここでは、コンテキストは this クラスです。connectedCallback() メソッドは、最上位の ready 変数に値を割り当てます。これは、Lightning Web コンポーネントを使用して開発に JavaScript 機能を取り入れる方法のよい例です。this に関する詳細情報へのリンクは、「リソース」セクションを参照してください。

駆け足で進んでいますが、いくつか試すことができました。次の単元では、一歩下がって、コンポーネントが存在する環境について説明します。

デコレータ

デコレータは、プロパティまたは関数の動作を変更するために JavaScript でよく使用されます。

デコレータを使用するには、lwc モジュールからインポートして、プロパティまたは関数の前に配置します。

import { LightningElement, api } from 'lwc';
export default class MyComponent extends LightningElement{
    @api message;
}

複数のデコレータをインポートできますが、1 つのプロパティまたは関数に設定できるデコレータは 1 つだけです。たとえば、プロパティに @api デコレータと @track デコレータを設定することはできません。

Lightning Web コンポーネントデコレータの例として、次のようなものがあります。

  • @api:: 項目を公開としてマークします。公開プロパティではコンポーネントの API を定義します。HTML マークアップでコンポーネントを使用する所有者コンポーネントは、コンポーネントの公開プロパティにアクセスできます。すべての公開プロパティはリアクティブです。つまり、フレームワークはプロパティの変更を監視します。プロパティの値が変更されると、フレームワークはそれに反応し、コンポーネントを再表示します。
    ヒント ヒント 項目とプロパティはほぼ同義の用語です。コンポーネントの作成者は JavaScript クラスで項目を宣言します。クラスのインスタンスはプロパティを持ちます。コンポーネントのコンシューマにとって、項目はプロパティです。Lightning Web コンポーネントでは、コンポーネントの作成者が @api でデコレートした項目のみが、オブジェクトプロパティとしてコンシューマに公開されます。
  • @track: オブジェクトのプロパティまたは配列の要素の変更を監視するようにフレームワークに指示します。変更があると、フレームワークはコンポーネントを再表示します。すべての項目はリアクティブです。項目の値が変更され、その項目がテンプレートで使用されているか、テンプレートで使用されているプロパティの getter で使用されている場合、フレームワークはコンポーネントを再表示します。項目を @track でデコレートする必要はありません。@track: は、項目にオブジェクトまたは配列が含まれていて、フレームワークでオブジェクトのプロパティまたは配列の要素の変更を監視する場合にのみ使用します。プロパティ全体の値を変更する場合は、@track を使用する必要はありません。
    メモ Spring '20 より前は、項目 (非公開プロパティともいう) をリアクティブとしてマークするために @track を使用しなければなりませんでしたが、これを行う必要はなくなりました。@track: は、オブジェクトのプロパティまたは配列の要素の変更を監視するようにフレームワークに指示する場合にのみ使用します。古い例の中には、必要がないのに @track がまだ使用されている場合がありますが、デコレータの使用によって機能が変更されたり、コードが壊れることはないので心配いりません。詳細は、こちらのリリースノートを参照してください。
  • @wire:: Salesforce からデータを簡単に取得してバインドできるようにします。

@api デコレータを使用して、あるコンポーネント (bike) の値を別のコンポーネント (app) に表示する例を次に示します。コンポーネントの Playground では、ファイルは次のようになります。 サンプルアプリケーションのファイル構造。

app コンポーネントは、次の HTML を使用します。

<!-- app.html -->
<template>
<div>
    <c-bike bike={bike}></c-bike>
</div>
</template>

app コンポーネントは、次の JavaScript を使用します。

// app.js
import { LightningElement } from 'lwc';
export default class App extends LightningElement {
    bike = {
        name: 'Electra X4',
        picture: 'https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax4.jpg'
    };
}

bike コンポーネントは、次の HTML を使用します。

<!-- bike.html -->
<template>
    <img src={bike.picture} alt="bike picture" />
    <p>{bike.name}</p>
</template>

bike コンポーネントは、次の JavaScript を使用します。

// bike.js
import { LightningElement, api } from 'lwc';
export default class Bike extends LightningElement {
    @api bike;
}

コンポーネントの Playground で @api デコレータのある場合とない場合を試して動作を確認してみてください。

ボーナス! Playground でコンポーネントを試しましょう

コンポーネントの Playground に慣れてきたので、少し時間を取って、Lightning Web コンポーネントレシピの例をいくつか試してください。リポジトリにある例から HTML、JavaScript、CSS をコンポーネントの Playground に貼り付けて試すことで、コンポーネントの基本概念を理解しやすくなります。

リソース