はじめに
Salesforceのレコードに紐づく画面をLWCで開発する際、@api recordId
と書いておくとそのrecordIdをプラットフォーム側が解決して、サーバー側に対してレコードに関する情報を要求できます。
レコードページにそのまま置くようなコンポーネントであればよいのですが、クイックアクションになるとちょっと微妙な点が出てきます。
それが、connectedCallback()
の時点ではまだrecordId
が解決されない点です。そのため、クイックアクションのconnectedCallback()
では、カスタムのApexアクションなどにrecordId
を使うことが難しいです。これを簡単に解決する小テクがあります。
動かない例
@AuraEnabled
なApexメソッドでrecordId
からレコードを紹介するパターンです。これはクイックアクション内では動かないです。(connectedCallback()
の実行がrecordId
の解決よりも先なので)
import someApexMethod from '@salesforce/apex/SomeClass.someApexMethod';
export default class QuickAction extends LightningElement {
@api recordId;
data;
async connectedCallback() {
this.data = await someApexMethod({ recordId: this.recordId }); // this.recordIdはundefined
}
}
動かす小テク
これを正攻法で解決するには@wire
を使うことですが、@wire
はキャッシュが強く残ったり不便なことが多いです。そのため、ちょっとした小テクを入れます。
具体的にはasync connectedCallback()
の冒頭にawait this.recordId;
と書いておきます。(本当はawaitするなら何でもいい)
import someApexMethod from '@salesforce/apex/SomeClass.someApexMethod';
export default class QuickAction extends LightningElement {
@api recordId;
data;
async connectedCallback() {
await this.recordId;
this.data = await someApexMethod({ recordId: this.recordId }); // this.recordIdは解決されている
}
}
解説
これがなぜ動くかを理解するには、以下の2点を理解する必要があります。
- LWCのライフサイクルフックの実行順
- JavaScriptにおけるイベントループ・タスクキュー・非同期処理の仕様
LWCのライフサイクルフックの実行順
大体こんな感じです。
constructor
connectedCallback
renderedCallback
-
wire
の結果が評価される
参考: https://salesforce.stackexchange.com/questions/377190/order-of-execution-of-wire-in-lwc
ここで大事なのは以下の2点です。
-
connectedCallback()
がwire
より先に実行される - クイックアクションのLWCでは、
recordId
がwire
のタイミングでクエリパラメータから解決される
JavaScriptの非同期処理
JSのasync関数は初めてのawaitより後の処理をthenハンドラとしてPromiseを返します。そして、そこでコールスタックを抜けるため、awaitより後の処理は後回しにされます。そのため、もともとの実行順が変化します。
constructor
-
connectedCallback
のawait以前 renderedCallback
-
wire
の結果が評価される←recordId解決 -
connectedCallback
のawaitより後の処理←recordIdを使う処理
今回のテクは無駄なawait
を書くことで、プラットフォームによるrecordId
の解決を待ってからconnectedCallback
を実行するようにしています。
awaitするのはなんでもいいのですが、recordIdを待つというのが意味的に分かりやすいのでawait this.recordId;
としています。
やってることはsetTimeout(~~~, 0)
とかのテクニックとほぼ同じです。