JavaScript の移行

学習の目的

この単元を完了すると、次のことができるようになります。
  • Aura コンポーネントから Lightning Web コンポーネントへ JavaScript を移行する。
  • Aura コンポーネントと Lightning Web コンポーネント間でコードを共有する。

JavaScript モジュールの使用

JavaScript は Lightning Web コンポーネントの鼓動する心臓です。JavaScript がなければ、コンポーネントは大部分が生気のない HTML の塊になります。前の単元では、Lightning Web コンポーネントの JavaScript ファイルを少しだけ見て、Aura コンポーネントの属性が JavaScript プロパティにどのようにマッピングされるのか確認しました。次は、JavaScript ファイルを詳しく見ていきます。

Aura コンポーネントのクライアント側コントローラ、ヘルパー、レンダラーの個別ファイルの JavaScript コードを、Lightning Web コンポーネントの 1 つの JavaScript ファイルに移行します。

Aura コンポーネントのクライアント側コントローラは、名前―値ペアのマッピングを含むオブジェクトリテラル表記法の JavaScript オブジェクトです。言葉数が多いですね。PropertyPaginatorController.js ファイルの例を見てみましょう。

({
	previousPage : function(component) {
        var pageChangeEvent = component.getEvent("pagePrevious");
        pageChangeEvent.fire();
	},
	nextPage : function(component) {
        var pageChangeEvent = component.getEvent("pageNext");
        pageChangeEvent.fire();
	}
})

Aura コンポーネントの JavaScript ファイルの形式は、JavaScript クラスやモジュールなどの機能の ES6 標準が確立される数年前に設計されました。

Lightning Web コンポーネントの JavaScript ファイルは ES6 モジュールなので、Aura コンポーネントで使用される専有形式ではなく、標準の JavaScript を使用しています。あなたが記述する JavaScript は、その他の最新の JavaScript フレームワーク向けに記述される JavaScript によく似ています。

以下は、paginator Lightning Web コンポーネントの JavaScript です。

import { LightningElement, api } from 'lwc';
export default class Paginator extends LightningElement {
    /** The current page number. */
    @api pageNumber;
    /** The number of items on a page. */
    @api pageSize;
    /** The total number of items in the list. */
    @api totalItemCount;
    previousHandler() {
        this.dispatchEvent(new CustomEvent('previous'));
    }
    nextHandler() {
        this.dispatchEvent(new CustomEvent('next'));
    }
    get currentPageNumber() {
        return this.totalItemCount === 0 ? 0 : this.pageNumber;
    }
    get isFirstPage() {
        return this.pageNumber === 1;
    }
    get isLastPage() {
        return this.pageNumber >= this.totalPages;
    }
    get totalPages() {
        return Math.ceil(this.totalItemCount / this.pageSize);
    }
}

コードを 1 行ずつ見ていくことはしません。主に重要なのは、Lightning Web コンポーネントでは標準の JavaScript モジュールが使用されるということです。それは良いことです。

Aura コンポーネントと Lightning Web コンポーネント間でのコードの共有

Lightning Web コンポーネントと Aura コンポーネントの間で JavaScript コードを共有するには、コードを ES6 モジュールに配置します。どちらのプログラミングモデルでも共有されたコードにアクセスできます。Lightning Web コンポーネントにすべてのコードを移行しない場合でも、Aura コンポーネントの ES6 モジュールで記述する新しい機能にアクセスできます。

utils.js ES6 モジュールの例を見てみましょう。

/* utils.js */
/**
 * Returns whether provided value is a function
 * @param {*} value - the value to be checked
 * @return {boolean} true if the value is a function, false otherwise
 */
export function isFunction(value) {
    return typeof value === 'function';
}

utils モジュールは、指定したパラメータが関数かどうかを返す isFunction() 関数をエクスポートします。

以下は、utils モジュールを使用する c-libcaller Lightning Web コンポーネントです。

/* libcaller.js */
import { LightningElement } from 'lwc';
// import the library
import { isFunction } from 'c/utils';
export default class LibCaller extends LightningElement {
    result;
    checkType() {
        // Call the imported library function
        this.result = isFunction(
            function() {
                console.log('I am a function');
            }
        ); 
    }
}

c-libcaller コンポーネントは utils モジュールをインポートし、モジュールによってエクスポートされた isFunction 関数をコールします。isFunction に渡される引数は関数なので、結果は true に設定されます。

次は、同じく utils モジュールを使用する libcallerAura.cmp ファイルを見てみましょう。

<aura:component>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <p>Aura component calling the utils lib</p>
    <!-- add the lib component -->
    <c:utils aura:id="utils" />
</aura:component>

libcallerAura Aura コンポーネントには c:utils ES6 モジュールへの参照が含まれています。JavaScript コードでモジュールの参照を取得できるように aura:id を追加しました。

以下は、libcallerAuraController.js ファイルです。

({
    doInit: function(cmp) {
        // Call the lib here
        var libCmp = cmp.find('utils');
        var result = libCmp.isFunction(
            function() {
                console.log(" I am a function");
            }
        );
        console.log("Is it a function?: " + result);
    }
})

コンポーネントのコントローラは cmp.find('utils') を使用して、マークアップの aura:id に一致させ、モジュールの参照を取得します。utils ES6 モジュールは isFunction() をエクスポートします。これは Aura コンポーネントをコールします。isFunction() に渡される引数は関数なので、結果は true に設定されます。

サードパーティ JavaScript ライブラリの使用

Aura コンポーネントまたは Lightning Web コンポーネントでサードパーティ JavaScript ライブラリを使用するには、ライブラリを静的リソースとしてアップロードする必要があります。静的リソースを操作する構文は、2 つのプログラミングモデルで異なります。

Aura コンポーネントでは、マークアップで <ltng:require> タグを使用して静的リソースを読み込みます。

<ltng:require scripts="{!$Resource.resourceName}"
    afterScriptsLoaded="{!c.afterScriptsLoaded}" />

resourceName が静的リソースの名前です。スクリプトが読み込まれると、クライアント側コントローラの afterScriptsLoaded アクションがコールされ、コンポーネントが表示されます。

Lightning Web コンポーネントでは、JavaScript で静的リソースをインポートします。

import resourceName from '@salesforce/resourceUrl/resourceName';

その後、loadScript と loadStyle を使用してサードパーティライブラリを読み込みます。

インポートされたライブラリの使用についての詳細は、『Lightning Web Components Developer Guide (Lightning Web コンポーネント開発者ガイド)』の「Use Third-Party JavaScript Libraries (サードパーティ JavaScript ライブラリの使用)」を参照してください。

コンポーネントの動的な作成

Aura コンポーネントでは、$A.createComponent() を使用して JavaScript でコンポーネントを動的に作成できます。Lightning Web コンポーネントには、コンポーネントの動的な作成に相当するものはありません。

このアーキテクチャに関する決定は意図的なものです。Lightning Web コンポーネントでこのパターンを再現しない主な理由は、Aura コンポーネントでは、このパターンがバグの多い複雑なコードにつながったからです。

改善策として、Lightning Web コンポーネントでは、コンポーネントに複数の HTML テンプレートを作成します。コンポーネントの render() メソッドで、コンポーネントのニーズに基づいてテンプレートを切り替えることができます。このパターンは、他の JavaScript フレームワークで使用されたルート分割により似ています。

リファクタリングの機会

JavaScript コードを移行するとき、それは 1 行ごとの変換ではありません。これはコンポーネントの設計を見直す良い機会です。

新しいプログラミングモデルへの移行は、同じ目的地につながる新しい道を進むようなものです。途中の景色や音 (そして記述するコード) が違います。

コンポーネントの移行は、Aura コンポーネントではおそらく使用していない JavaScript モジュールなどの新しい ES6 機能を使用する良い機会でもあります。

これらの新機能の概要は、「JavaScript の最新機能」 Trailhead モジュールを参照してください。

リソース