こんにちは、アンダーソンです。
今回はLWCでのデコレータのそれぞれの役割についてまとめました。
先日実施した、LWCのスーパーバッチでもデコレータの付け方までみられます。
デコレータをうまく使うことでコンポーネントをネストしたり、動的に変更したり、
Apexを参照したりすることが可能になりますので、
是非それぞれの役割を抑えておいてください。
デコレータを使うための前準備
まずデコレータを使う前に、モジュールを読み込んでおく必要があります。
import { LightningElement, api, track, wire } from 'lwc';
これでOKです。
コードをみていただいてわかるようにLWCでは
標準で3つのデコレータがサポートされています。
- api
- track
- wire
それぞれのデコレータは変数や関数につけることができますが、
重複して(例えばapiとwireを1つの変数につける)などはできないので
注意しましょう。
それぞれ、宣言時に@apiの形式でつけていきます。
@api hasChanged;
ではそれぞれの役割をみていきたいと思います。
@apiはいわゆるpublic
まずは@apiからです。
このデコレータの役割は公開です。
他のコンポーネントから参照できるようにでき、
他のコンポーネントはこの変数や関数に対して値をインプットすることができるようになります。
では実際に例を作ってみましたのでみていきましょう。
import { LightningElement,api } from 'lwc';
export default class SampleComponent extends LightningElement {
@api isChanged;
}
isChangedという変数を公開状態にしています。
それを親のコンポーネントからこのコンポーネントに対して値を渡してあげます。
その変数に対して、親側から値を入れてあげます。
<template>
<c-sample-component is-changed={isChanged}></c-sample-component>
<lightning-button onclick={flgChange} label="変更"></lightning-button>
</template>
import { LightningElement } from 'lwc';
export default class ParentSampleComponent extends LightningElement {
isChanged = false;
flgChange(){
if ( this.isChanged ) {
this.isChanged = false;
} else {
this.isChanged = true;
}
}
}
これでOKです。
下記のような画面が作れると思います。
@trackはリレンダーしたい時につけよう
次はtrackデコレータです。
trackデコレータは元々、変数などの値が変わった時に、
含まれているコンポーネントを再描画するための物だったようなのですが、
Spring’20の更新でつけなくても再描画されるようになりました。
ではどのような時につけるのかですが、
下記のようにリストの一部だけが変更するというような場合は
trackデコレータ無しでは再描画されません。
fullName = [ {firstName: "",lastName: "" }];
onChange(event){
this.fullName.firstName = event.target.value;
}
この場合にonChange関数に値が入ってきたとしても、
firstNameのみの変更なので、プロパティが監視されていないため変更は
適用されません。
そのため、上記の例だと、fullName自体に@trackをつけてやる必要があります。
@track fullName = [ {firstName: "",lastName: "" }];
HTML側は下記のようにしています。
<template>
<lightning-card>
{fullName.firstName}
<lightning-input label="名前入力" onchange={onChange}></lightning-input>
</lightning-card>
</template>
これで下記のようにfirstNameのみ変更されるイベントでもちゃんと変更されました。
wireサービスで組織と繋がる
最後はwireデコレータです。
wireサービスは組織のデータを取得するのに必須のデコレータです。
まずはApexを使用しない方法です。
import { LightningElement,wire,api } from 'lwc';
import { getRecord } from 'lightning/uiRecordApi';
const FIELDS = [
'Contact.Name'
];
export default class ParentSampleComponent extends LightningElement {
@api recordId;
@wire(getRecord,{ recordId: '$recordId' , fields: FIELDS })
contact;
get Name(){
if ( this.contact.data ) {
return this.contact.data.fields.Name.value;
} else {
return null;
}
}
}
まず、2行目のimport { getRecord } from ‘lightning/uiRecordApi’;で標準の
レコード取得のモジュールを読み込んでおきます。
次に@api宣言しておいたrecordIdには画面が読み込まれた際にレコードのIdが
入ってくる想定です。(これについてはレコード詳細画面を想定)
そして@wire(getRecord,{ recordId: ‘$recordId’ , fields: FIELDS })であらかじめ項目を決めておいた値をrecordIdの値によって取得するといった流れです。
これについてはそこまで難しくありません。
次にApexを使用したやり方です。
Apexを使用する際は@AuraEnabledをつけたメソッドがあるクラスしか呼び出せません。
これもあらかじめモジュールとしてApexを読み込んでおくことになります。
今回は下記のモジュールでApexを呼び出します。
import getContactName from '@salesforce/apex/myComponentController.getContactName'
これでmyComponentControllerというクラスのgetContactNameというメソッドを呼び出すことができます。ちなみにクラス側はこんな感じです。
@AuraEnabled(Cacheable=true)
public static List<Contact> getContactName(){
return [
SELECT
Id,
Name
FROM Contact
order by Name
LIMIT 1
];
}
ではこれをwireデコレータを使って呼び出してみましょう。
@wire(getContactName)
contacts;
これだけでOKです。
簡単ですよね。
Apexの戻り値が配列なので、今回はHTML側を少し工夫してあげました。
<template>
<lightning-card>
<template for:each={contacts.data} for:item="contact">
<li key={contact.Id}>
{contact.Name}
</li>
</template>
</lightning-card>
</template>
これでApexから取得したレコードを取得することができました。
今回記載した方法は全て基本的な物なので、是非ドキュメントをみながら
いろいろな方法も試してみてください。