ライフサイクル
Litコンポーネントは、標準的なカスタムエレメントのライフサイクルメソッドを使用します。さらに、Litは、リアクティブプロパティが変更されたときにDOMの変更をレンダリングするリアクティブ更新サイクルを導入しています。
標準的なカスタムエレメントのライフサイクル
「標準的なカスタムエレメントのライフサイクル」へのパーマリンクLitコンポーネントは標準的なカスタムエレメントであり、カスタムエレメントのライフサイクルメソッドを継承します。カスタムエレメントのライフサイクルに関する情報は、MDNのライフサイクルコールバックの使用を参照してください。
標準的なカスタムエレメントのライフサイクルメソッドをカスタマイズする必要がある場合は、標準的なLitの機能を維持するために、必ずsuperの実装(例:super.connectedCallback())を呼び出してください。
constructor()
「constructor()」へのパーマリンク要素が作成されたときに呼び出されます。また、既存の要素がアップグレードされたときにも呼び出されます。これは、カスタムエレメントの定義が、要素がすでにDOMにある後にロードされた場合に発生します。
Litの動作
「Litの動作」へのパーマリンクrequestUpdate()メソッドを使用して非同期更新を要求するため、Litコンポーネントがアップグレードされると、すぐに更新を実行します。
要素に既に設定されているプロパティを保存します。これにより、アップグレード前に設定された値が維持され、コンポーネントによって設定されたデフォルト値が正しく上書きされます。
ユースケース
「ユースケース」へのパーマリンク最初の更新の前に実行する必要がある、一度限りの初期化タスクを実行します。たとえば、デコレータを使用しない場合、静的プロパティフィールドでプロパティを宣言するに示されているように、コンストラクタでプロパティのデフォルト値を設定できます。
constructor() { super(); this.foo = 'foo'; this.bar = 'bar';}connectedCallback()
「connectedCallback()」へのパーマリンクコンポーネントがドキュメントのDOMに追加されたときに呼び出されます。
Litの動作
「Litの動作」へのパーマリンクLitは、要素が接続された後に最初の要素更新サイクルを開始します。レンダリングの準備として、LitはrenderRoot(通常はshadowRoot)が作成されていることを確認します。
要素が少なくとも一度ドキュメントに接続されると、要素の接続状態に関係なく、コンポーネントの更新は続行されます。
ユースケース
「ユースケース」へのパーマリンクconnectedCallback()では、要素がドキュメントに接続されている場合にのみ発生する必要があるタスクを設定する必要があります。これらで最も一般的なのは、ウィンドウに追加されたkeydownイベントハンドラなど、要素の外部のノードにイベントリスナーを追加することです。通常、connectedCallback()で行われることは、要素が切断されたときに元に戻す必要があります。たとえば、メモリリークを防ぐためにウィンドウのイベントリスナーを削除します。
connectedCallback() { super.connectedCallback() window.addEventListener('keydown', this._handleKeydown);}disconnectedCallback()
「disconnectedCallback()」へのパーマリンクコンポーネントがドキュメントのDOMから削除されたときに呼び出されます。
Litの動作
「Litの動作」へのパーマリンクリアクティブ更新サイクルを一時停止します。要素が接続されると再開されます。
ユースケース
「ユースケース」へのパーマリンクこのコールバックは、要素がもう使用されない可能性があることを要素に知らせる主要なシグナルです。そのため、disconnectedCallback()では、要素(要素の外部のノードに追加されたイベントリスナーなど)への参照を何も保持していないことを確認する必要があります。これにより、ガベージコレクションされることができます。要素は、DOM内の要素の移動やキャッシングの場合のように、切断された後に再接続される可能性があるため、そのような参照やリスナーは、connectedCallback()を介して再確立する必要がある場合があります。これにより、要素はこれらのシナリオで期待どおりに機能し続けます。たとえば、ウィンドウに追加されたkeydownイベントハンドラなど、要素の外部のノードのイベントリスナーを削除します。
disconnectedCallback() { super.disconnectedCallback() window.removeEventListener('keydown', this._handleKeydown);}内部イベントリスナーを削除する必要はありません。テンプレートで宣言的に追加されたものを含め、コンポーネント自身のDOMに追加されたイベントリスナーを削除する必要はありません。外部イベントリスナーとは異なり、これらはコンポーネントがガベージコレクションされるのを防ぎません。
attributeChangedCallback()
「attributeChangedCallback()」へのパーマリンク要素のobservedAttributesのいずれかが変更されたときに呼び出されます。
Litの動作
「Litの動作」へのパーマリンクLitは、このコールバックを使用して、属性の変更をリアクティブプロパティに同期します。具体的には、属性が設定されると、対応するプロパティが設定されます。Litは、コンポーネントのリアクティブプロパティのリストと一致するように、要素のobservedAttributes配列を自動的に設定します。
ユースケース
「ユースケース」へのパーマリンクこのコールバックを実装する必要があることはめったにありません。
adoptedCallback()
「adoptedCallback()」へのパーマリンクコンポーネントが新しいドキュメントに移動されたときに呼び出されます。
adoptedCallbackはポリフィルされていないことに注意してください。
Litの動作
「Litの動作」へのパーマリンクLitには、このコールバックに対するデフォルトの動作はありません。
ユースケース
「ユースケース」へのパーマリンクこのコールバックは、要素の動作がドキュメントが変更されたときに変更される必要がある高度なユースケースでのみ使用する必要があります。
リアクティブ更新サイクル
「リアクティブ更新サイクル」へのパーマリンク標準的なカスタムエレメントのライフサイクルに加えて、Litコンポーネントはリアクティブ更新サイクルも実装しています。
リアクティブ更新サイクルは、リアクティブプロパティが変更された場合、またはrequestUpdate()メソッドが明示的に呼び出された場合にトリガーされます。Litは更新を非同期的に実行するため、プロパティの変更はバッチ処理されます。更新が要求された後、更新が開始する前にさらにプロパティが変更された場合、すべての変更は同じ更新で取得されます。
更新はマイクロタスクタイミングで行われます。つまり、ブラウザが次のフレームを画面にペイントする前に発生します。ブラウザのタイミングの詳細については、Jake Archibaldの記事を参照してください。
高いレベルでは、リアクティブ更新サイクルは次のとおりです。
- 1つ以上のプロパティが変更された場合、または
requestUpdate()が呼び出された場合、更新がスケジュールされます。 - 次のフレームがペイントされる前に更新が実行されます。
- 反映属性が設定されます。
- コンポーネントのレンダリングメソッドが呼び出され、内部DOMが更新されます。
- 更新が完了し、
updateCompleteプロミスが解決されます。
より詳細には、次のようになります。
更新前


更新

更新後

changedProperties マップ
「changedPropertiesマップ」へのパーマリンク多くのリアクティブ更新メソッドは、変更されたプロパティのMapを受け取ります。Mapのキーはプロパティ名であり、その値は以前のプロパティ値です。現在のプロパティ値は、常にthis.propertyまたはthis[property]を使用して取得できます。
changedPropertiesのTypeScript型
「changedPropertiesのTypeScript型」へのパーマリンクTypeScriptを使用していて、changedPropertiesマップの厳密な型チェックが必要な場合は、各プロパティ名に正しい型を推論するPropertyValues<this>を使用できます。
import {LitElement, html, PropertyValues} from 'lit';... shouldUpdate(changedProperties: PropertyValues<this>) { ... }厳密な型付けをあまり気にしない場合、またはプロパティ名のみをチェックしていて、以前の値はチェックしない場合は、Map<string, any>などの制限の少ない型を使用できます。
PropertyValues<this>は、protectedまたはprivateプロパティを認識しません。protectedまたはprivateプロパティをチェックする場合は、制限の少ない型を使用する必要があります。
更新中にプロパティを変更する
「更新中にプロパティを変更する」へのパーマリンク更新中(render()メソッドを含む)にプロパティを変更すると、changedPropertiesマップは更新されますが、新しい更新はトリガーされません。render()の後(たとえば、updated()メソッド内)にプロパティを変更すると、新しい更新サイクルがトリガーされ、変更されたプロパティは次のサイクルで使用される新しいchangedPropertiesマップに追加されます。
更新のトリガー
「更新のトリガー」へのパーマリンクリアクティブプロパティが変更された場合、またはrequestUpdate()メソッドが呼び出された場合、更新がトリガーされます。更新は非同期的に実行されるため、更新が実行される前に発生したすべての変更は、単一の更新のみになります。
hasChanged()
「hasChanged()」へのパーマリンクリアクティブプロパティが設定されたときに呼び出されます。デフォルトでは、hasChanged()は厳密な等価性チェックを行い、trueを返す場合、更新がスケジュールされます。詳細については、hasChanged()の設定を参照してください。
requestUpdate()
「requestUpdate()」へのパーマリンク明示的な更新をスケジュールするには、requestUpdate() を呼び出します。これは、プロパティに関連しない何かが変更されたときに要素を更新してレンダリングする必要がある場合に役立ちます。たとえば、タイマーコンポーネントは毎秒requestUpdate()を呼び出す場合があります。
connectedCallback() { super.connectedCallback(); this._timerInterval = setInterval(() => this.requestUpdate(), 1000);}
disconnectedCallback() { super.disconnectedCallback(); clearInterval(this._timerInterval);}変更されたプロパティのリストは、後続のライフサイクルメソッドに渡されるchangedPropertiesマップに格納されます。マップのキーはプロパティ名、値は以前のプロパティ値です。
オプションで、requestUpdate()を呼び出す際にプロパティ名と以前の値を渡すことができます。これは、changedPropertiesマップに格納されます。これは、プロパティのカスタムゲッターとセッターを実装する場合に役立ちます。カスタムゲッターとセッターの実装の詳細については、「リアクティブプロパティ」を参照してください。
this.requestUpdate('state', this._previousState);更新の実行
「更新の実行」へのパーマリンク更新が実行されると、performUpdate()メソッドが呼び出されます。このメソッドは、他のいくつかのライフサイクルメソッドを呼び出します。
通常は更新をトリガーする変更で、コンポーネントが更新されている**間**に発生したものは、**新しい更新をスケジュールしません**。これは、更新プロセス中にプロパティ値を計算できるようにするためです。更新中に変更されたプロパティは、changedPropertiesマップに**反映される**ため、後続のライフサイクルメソッドは変更内容を処理できます。
shouldUpdate()
「shouldUpdate()」へのパーマリンク更新サイクルが必要かどうかを判断するために呼び出されます。
| 引数 | changedProperties: 変更されたプロパティの名前をキーとし、対応する以前の値を値とするMap。 |
| 更新 | いいえ。このメソッド内のプロパティの変更は、要素の更新をトリガーしません。 |
| super の呼び出し? | 不要です。 |
| サーバー上で呼び出される? | いいえ。 |
shouldUpdate()がデフォルトでtrueを返す場合、更新は通常どおりに進みます。falseを返す場合、更新サイクルの残りの部分は呼び出されませんが、updateComplete Promise は解決されたままです。
どのプロパティの変更が更新を引き起こすべきかを指定するために、shouldUpdate()を実装できます。changedPropertiesのマップを使用して、現在の値と以前の値を比較します。
shouldUpdate(changedProperties: Map<string, any>) { // Only update element if prop1 changed. return changedProperties.has('prop1'); }shouldUpdate(changedProperties) { // Only update element if prop1 changed. return changedProperties.has('prop1');}willUpdate()
「willUpdate()」へのパーマリンク更新中に必要な値を計算するために、update()の前に呼び出されます。
| 引数 | changedProperties: 変更されたプロパティの名前をキーとし、対応する以前の値を値とするMap。 |
| 更新? | いいえ。このメソッド内のプロパティの変更は、要素の更新をトリガーしません。 |
| super の呼び出し? | 不要です。 |
| サーバー上で呼び出される? | はい。 |
他のプロパティに依存し、更新プロセスの残りの部分で使用されるプロパティ値を計算するには、willUpdate()を実装します。
willUpdate(changedProperties: PropertyValues<this>) { // only need to check changed properties for an expensive computation. if (changedProperties.has('firstName') || changedProperties.has('lastName')) { this.sha = computeSHA(`${this.firstName} ${this.lastName}`); }}
render() { return html`SHA: ${this.sha}`;}willUpdate(changedProperties) { // only need to check changed properties for an expensive computation. if (changedProperties.has('firstName') || changedProperties.has('lastName')) { this.sha = computeSHA(`${this.firstName} ${this.lastName}`); }}
render() { return html`SHA: ${this.sha}`;}update()
「update()」へのパーマリンクコンポーネントのDOMを更新するために呼び出されます。
| 引数 | changedProperties: 変更されたプロパティの名前をキーとし、対応する以前の値を値とするMap。 |
| 更新? | いいえ。このメソッド内のプロパティの変更は、要素の更新をトリガーしません。 |
| super の呼び出し? | はい。super の呼び出しがないと、要素の属性とテンプレートは更新されません。 |
| サーバー上で呼び出される? | いいえ。 |
プロパティ値を属性に反映し、render()を呼び出してコンポーネントの内部DOMを更新します。
一般的に、このメソッドを実装する必要はありません。
render()
「render()」へのパーマリンクupdate()によって呼び出され、コンポーネントのDOMをレンダリングするために使用されるレンダリング可能な結果(TemplateResultなど)を返すために実装する必要があります。
| 引数 | なし。 |
| 更新? | いいえ。このメソッド内のプロパティの変更は、要素の更新をトリガーしません。 |
| super の呼び出し? | 不要です。 |
| サーバー上で呼び出される? | はい。 |
render()メソッドには引数はありませんが、通常はコンポーネントのプロパティを参照します。詳細については、「レンダリング」を参照してください。
render() { const header = `<header>${this.header}</header>`; const content = `<section>${this.content}</section>`; return html`${header}${content}`;}更新の完了
「更新の完了」へのパーマリンクupdate()が呼び出されてコンポーネントのDOMへの変更がレンダリングされた後、これらのメソッドを使用してコンポーネントのDOMでアクションを実行できます。
firstUpdated()
「firstUpdated()」へのパーマリンクupdated()が呼び出される直前に、コンポーネントのDOMが初めて更新された後に呼び出されます。
| 引数 | changedProperties: 変更されたプロパティの名前をキーとし、対応する以前の値を値とするMap。 |
| 更新? | はい。このメソッド内のプロパティの変更は、新しい更新サイクルをスケジュールします。 |
| super の呼び出し? | 不要です。 |
| サーバー上で呼び出される? | いいえ。 |
コンポーネントのDOMが作成された後、一度だけ作業を実行するには、firstUpdated()を実装します。例としては、特定のレンダリングされた要素にフォーカスを当てたり、要素にResizeObserverまたはIntersectionObserverを追加することがあります。
firstUpdated() { this.renderRoot.getElementById('my-text-area').focus();}updated()
「updated()」へのパーマリンクコンポーネントの更新が終了し、要素のDOMが更新およびレンダリングされるたびに呼び出されます。
| 引数 | changedProperties: 変更されたプロパティの名前をキーとし、対応する以前の値を値とするMap。 |
| 更新? | はい。このメソッド内のプロパティの変更は、要素の更新をトリガーします。 |
| super の呼び出し? | 不要です。 |
| サーバー上で呼び出される? | いいえ。 |
更新後に要素DOMを使用するタスクを実行するには、updated()を実装します。たとえば、アニメーションを実行するコードは、要素DOMを測定する必要がある場合があります。
updated(changedProperties: Map<string, any>) { if (changedProperties.has('collapsed')) { this._measureDOM(); }}updated(changedProperties) { if (changedProperties.has('collapsed')) { this._measureDOM(); }}updateComplete
「updateComplete」へのパーマリンクupdateCompleteプロミスは、要素の更新が完了すると解決されます。更新を待つには、updateCompleteを使用します。解決された値は、要素の更新が完了したかどうかを示すブール値です。更新サイクルが終了した後、保留中の更新がない場合、trueになります。
要素が更新されると、その子要素も更新される場合があります。デフォルトでは、updateCompleteプロミスは要素の更新が完了したときに解決されますが、子要素の更新が完了するのを待ちません。getUpdateCompleteをオーバーライドすることで、この動作をカスタマイズできます。
要素の更新が完了した時点を知る必要があるいくつかのユースケースがあります。
テスト テストを作成する場合、コンポーネントのDOMに関するアサーションを行う前に、
updateCompleteプロミスを待機できます。アサーションがコンポーネントの全体の子ツリーの更新の完了に依存する場合は、Litのデフォルトのスケジューリングはブラウザーのmicrotaskキューを使用するため(アニメーションフレームの前に空になります)、requestAnimationFrameを待機する方が多くの場合適切です。これにより、requestAnimationFrameコールバックの前に、ページ上の保留中のすべてのLit更新が完了していることが保証されます。測定 一部のコンポーネントでは、特定のレイアウトを実装するためにDOMを測定する必要があります。JavaScriptベースの測定ではなく、純粋なCSSを使用してレイアウトを実装する方が常に優れていますが、CSSの制限により避けられない場合があります。非常に単純なケースで、LitまたはReactiveElementコンポーネントを測定している場合は、状態の変更後および測定前に
updateCompleteを待機するだけで十分な場合があります。ただし、updateCompleteはすべての子孫の更新を待機しないため、レイアウトが変更されたときに測定コードをトリガーするより堅牢な方法として、ResizeObserverを使用することをお勧めします。イベント レンダリングが完了した後にコンポーネントからイベントをディスパッチする方が良い習慣です。そのため、イベントのリスナーはコンポーネントの完全にレンダリングされた状態を確認できます。これを行うには、イベントを発生させる前に
updateCompleteプロミスを待機できます。async _loginClickHandler() {this.loggedIn = true;// Wait for `loggedIn` state to be rendered to the DOMawait this.updateComplete;this.dispatchEvent(new Event('login'));}
更新サイクル中に未処理のエラーが発生すると、updateCompleteプロミスは拒否されます。詳細については、「更新サイクルでのエラーの処理」を参照してください。
更新サイクルでのエラー処理
「更新サイクルでのエラーの処理」へのパーマリンクrender()またはupdate()などのライフサイクルメソッドで未処理の例外が発生すると、updateCompleteプロミスが拒否されます。例外をスローする可能性のあるライフサイクルメソッドにコードがある場合は、try/catchステートメント内に配置することをお勧めします。
updateCompleteプロミスを待機している場合も、try/catchを使用することをお勧めします。
try { await this.updateComplete;} catch (e) { /* handle error */}場合によっては、予期しない場所でコードがスローされる場合があります。フォールバックとして、これらの問題をキャッチするためにwindow.onunhandledrejectionのハンドラーを追加できます。たとえば、これを使用して、再現が困難な問題の診断に役立つように、エラーをバックエンドサービスに報告できます。
window.onunhandledrejection = function(e) { /* handle error */}追加のカスタマイズの実装
「追加のカスタマイズの実装」へのパーマリンクこのセクションでは、更新サイクルをカスタマイズするためのあまり一般的ではないメソッドについて説明します。
scheduleUpdate()
「scheduleUpdate()」へのパーマリンク更新のタイミングをカスタマイズするには、scheduleUpdate()をオーバーライドします。scheduleUpdate()は更新が実行されようとしているときに呼び出され、デフォルトではすぐにperformUpdate()を呼び出します。更新を遅らせるためにオーバーライドします。この手法は、メインのレンダリング/イベントスレッドのブロックを解除するために使用できます。
たとえば、次のコードは、次のフレームの描画後に更新が実行されるようにスケジュールします。これは、更新にコストがかかる場合にジャンクを削減できます。
protected override async scheduleUpdate(): Promise<void> { await new Promise((resolve) => setTimeout(resolve)); super.scheduleUpdate();}async scheduleUpdate() { await new Promise((resolve) => setTimeout(resolve)); super.scheduleUpdate();}scheduleUpdate()をオーバーライドする場合は、保留中の更新を実行するためにsuper.scheduleUpdate()を呼び出す必要があります。
非同期関数はオプションです。
この例は、暗黙的にプロミスを返す非同期関数を示しています。scheduleUpdate()を明示的にPromiseを返す関数として記述することもできます。どちらの場合も、scheduleUpdate()によって返されたプロミスが解決されるまで、**次の**更新は開始されません。
performUpdate()
「performUpdate()」へのパーマリンクshouldUpdate()、update()、updated()などの他のメソッドを呼び出すことで、リアクティブな更新サイクルを実装します。
保留中の更新をすぐに処理するには、performUpdate()を呼び出します。これは一般的に必要ありませんが、同期的に更新する必要があるまれなケースでは実行できます。(保留中の更新がない場合は、requestUpdate()を呼び出してからperformUpdate()を呼び出すことで、強制的に同期更新を行うことができます。)
スケジューリングをカスタマイズするには、scheduleUpdate()を使用します。
更新のスケジュール方法をカスタマイズする場合は、scheduleUpdate()をオーバーライドします。以前は、この目的のためにperformUpdate()をオーバーライドすることをお勧めしていました。それは引き続き機能しますが、保留中の更新を同期的に処理するためにperformUpdate()を呼び出すことをより困難にします。
hasUpdated
「hasUpdated」へのパーマリンクhasUpdatedプロパティは、コンポーネントが少なくとも1回更新された場合にtrueを返します。コンポーネントがまだ更新されていない場合にのみ作業を実行するには、ライフサイクルメソッドのいずれかでhasUpdatedを使用できます。
getUpdateComplete()
「getUpdateComplete()」へのパーマリンクupdateCompleteプロミスを満たす前に追加の条件を待機するには、getUpdateComplete()メソッドをオーバーライドします。たとえば、子要素の更新を待機することが役立つ場合があります。最初にsuper.getUpdateComplete()を待機してから、後続の状態を待機します。
TypeScriptのES5出力を使用しているユーザーとの互換性を確保するために、updateCompleteゲッターではなくgetUpdateComplete()メソッドをオーバーライドすることをお勧めします(TypeScript#338を参照)。
class MyElement extends LitElement { async getUpdateComplete() { const result = await super.getUpdateComplete(); await this._myChild.updateComplete; return result; }}外部ライフサイクルフック:コントローラとデコレータ
“外部ライフサイクルフック:コントローラーとデコレーター”へのパーマリンクコンポーネントクラスがライフサイクルコールバックを実装することに加えて、デコレーターなどの外部コードがコンポーネントのライフサイクルにフックする必要がある場合があります。
Litは、外部コードがリアクティブな更新ライフサイクルと統合するための2つの概念を提供します。static addInitializer()とaddController()です。
static addInitializer()
“static addInitializer()”へのパーマリンクaddInitializer()を使用すると、Litクラス定義にアクセスできるコードは、クラスのインスタンスが構築されるときにコードを実行できます。
これは、カスタムデコレーターを作成する場合に非常に役立ちます。デコレーターはクラス定義時に実行され、フィールドとメソッドの定義を置き換えるなどの処理を行うことができます。インスタンスが作成されたときに作業を行う必要がある場合も、addInitializer()を呼び出す必要があります。これは、リアクティブコントローラーを追加するために一般的に使用されるため、デコレーターはコンポーネントのライフサイクルにフックできます。
// A TypeScript decoratorconst myDecorator = (proto: ReactiveElement, key: string) => { const ctor = proto.constructor as typeof ReactiveElement;
ctor.addInitializer((instance: ReactiveElement) => { // This is run during construction of the element new MyController(instance); });};// A Babel "Stage 2" decoratorconst myDecorator = (descriptor) => { ...descriptor, finisher(ctor) { ctor.addInitializer((instance) => { // This is run during construction of the element new MyController(instance); }); },};フィールドをデコレートすると、各インスタンスでコントローラーを追加するイニシャライザーが実行されます。
class MyElement extends LitElement { @myDecorator foo;}イニシャライザーはコンストラクターごとに保存されます。サブクラスにイニシャライザーを追加しても、スーパークラスに追加されません。イニシャライザーはコンストラクターで実行されるため、イニシャライザーはスーパークラスから開始してインスタンスのクラスに進むというクラス階層の順序で実行されます。
addController()
“addController()”へのパーマリンクaddController()は、Litコンポーネントにリアクティブコントローラーを追加して、コンポーネントがコントローラーのライフサイクルコールバックを呼び出すようにします。リアクティブコントローラーのドキュメントで詳細を確認してください。
removeController()
“removeController()”へのパーマリンクremoveController()は、リアクティブコントローラーを削除するため、このコンポーネントからライフサイクルコールバックを受け取らなくなります。
サーバーサイドリアクティブ更新サイクル
“サーバーサイドリアクティブ更新サイクル”へのパーマリンクLitのサーバーサイドレンダリングパッケージは現在開発中であるため、以下の情報は変更される可能性があります。
サーバーでLitをレンダリングする場合、更新サイクル全体が呼び出されるわけではありません。サーバーで呼び出されるメソッドを以下に示します。
