Blazor コンポーネント ライフサイクルを理解する
- 7 分
Blazor コンポーネントには明確に定義されたライフサイクルがあります。それは最初に作成されたときに始まり、破棄されたときに終了します。 特定のトリガーに応答して発生する一連のイベントによって、コンポーネントのライフサイクルが制御されます。 このようなトリガーには、コンポーネントの初期化、ユーザーとコンポーネントの対話、コンポーネントが存在するページの終了などが含まれます。
このユニットでは、Blazor コンポーネントのライフサイクル中に発生するイベントについて学習します。 これらのイベントを処理して、行われる作業を最適化し、Blazor ページの応答性を向上させる方法を確認します。
Blazor コンポーネント ライフサイクル
Blazor コンポーネントは Blazor アプリのビューを表し、これによりレイアウトと UI ロジックが定義されます。 コンポーネントによって、アプリの実行時に HTML マークアップが生成されます。 ユーザーとの対話イベントによってカスタム コードをトリガーでき、コンポーネントを更新して表示を再レンダリングできます。 ページを閉じると、Blazor によってコンポーネントが削除され、すべてのリソースがクリーンアップされます。 ユーザーがページに戻ると、新しいインスタンスが作成されます。
次の図は、コンポーネントの有効期間中に発生するイベントと、これらのイベントを処理するために使用できるメソッドを示しています。
SetParametersAsync を除き、Blazor には、各メソッドの同期および非同期の両方のバージョンが用意されています。
すべての Blazor コンポーネントは、表示されるメソッドを定義し、既定の動作を提供する ComponentBase クラスまたは IComponent インターフェイスから派生します。 イベントは、対応するメソッドをオーバーライドすることによって処理します。
この図は、ライフサイクル メソッド間にシングルスレッド フローが存在することを示していますが、これらのメソッドの非同期バージョンを使用すると Blazor アプリでレンダリング プロセスを迅速化できます。 たとえば、await で最初の SetParametersAsync が発生したとき、Blazor コンポーネントで OnInitialized および OnInitializedAsync メソッドが実行されます。 待機中のステートメントが完了すると、SetParametersAsync 内の実行スレッドが再開されます。
この同じロジックが、一連のライフサイクル メソッドの全体にわたって適用されます。 また、awaitおよびOnInitializedAsync中に発生する各OnParametersSetAsync操作は、コンポーネントの状態が変更されたことを示し、ページの即時レンダリングをトリガーできます。 初期化が完全に完了する前に、ページが複数回レンダリングされる可能性があります。
ライフサイクル メソッドを理解する
コンポーネント ライフサイクルの各メソッドには特定の目的があり、メソッドをオーバーライドしてコンポーネントにカスタム ロジックを追加できます。 次の表では、ライフサイクル メソッドを発生する順に一覧表示し、その目的について説明しています。
| Order | ライフサイクル メソッド | Description |
|---|---|---|
| 1 | 作成されたコンポーネント | コンポーネントがインスタンス化されます。 |
| 2 | SetParametersAsync | レンダリング ツリー内のコンポーネントの親からパラメーターを設定します。 |
| 3 | OnInitialized / OnInitializedAsync | コンポーネントを開始する準備ができると発生します。 |
| 4 | OnParametersSet / OnParametersSetAsync | コンポーネントがパラメーターを受け取ると発生し、プロパティが割り当てられます。 |
| 5 | OnAfterRender / OnAfterRenderAsync | コンポーネントがレンダリングされた後に発生します。 |
| 6 | Dispose / DisposeAsync |
コンポーネントが IDisposable または IAsyncDisposable を実装している場合、コンポーネントを破棄する一環として適切な破棄が行われます。 |
SetParametersAsync メソッド
ユーザーが Blazor コンポーネントを含むページにアクセスすると、Blazor ランタイムによってコンポーネントの新しいインスタンスが作成され、既定のコンストラクターが実行されます。 コンポーネントが構築されると、Blazor ランタイムによって SetParametersAsync メソッドが呼び出されます。
コンポーネントでパラメーターが定義されている場合は、Blazor ランタイムによって、これらのパラメーターの値が呼び出し元の環境からそのコンポーネントに挿入されます。 これらのパラメーターは ParameterView オブジェクトに含まれており、SetParametersAsync メソッドからアクセスできるようになります。 これらの値をコンポーネントの base.SetParametersAsync プロパティに入力するには、Parameter メソッドを呼び出します。
または、これらのパラメーターを別の方法で処理する必要がある場合は、このメソッドでそれを行います。 たとえば、コンポーネントに渡されたすべてのパラメーターの使用前の検証が必要になることがあります。
Note
SetParametersAsync メソッドは、コンポーネントにパラメーターがない場合でも、そのコンポーネントが作成されたときに常に実行されます。
OnInitialized および OnInitializedAsync メソッド
OnInitialized および OnInitializedAsync メソッドをオーバーライドして、カスタム機能を追加することができます。 これらは、SetParametersAsync メソッドによってコンポーネントのパラメーターベースのプロパティ (ParameterAttribute または CascadingParameterAttribute の属性が設定されている) が設定された後に実行されます。 これらのメソッドで初期化ロジックを実行します。
アプリケーションの render-mode プロパティが Server に設定されている場合、OnInitialized および OnInitializedAsync メソッドはコンポーネント インスタンスに対して一度だけ実行されます。 コンポーネント パラメーターがそのコンポーネントの親によって変更された場合、SetParametersAsync メソッドはもう一度実行されますが、これらのメソッドは実行されません。 パラメーターが変更されたときにコンポーネントを再初期化する必要がある場合は、SetParametersAsync メソッドを使用します。 初期化を 1 回実行したい場合は、これらのメソッドを使用します。
render-mode プロパティが ServerPrerendered に設定されている場合、OnInitialized および OnInitializedAsync メソッドは 2 回実行されます。静的なページ出力を生成するプリレンダリング フェーズ中に 1 回と、サーバーでブラウザーとの SignalR 接続が確立されたときにもう 1 回です。 これらのメソッドでは、Blazor コンポーネントの状態を設定するために使用するデータを Web サービスから取得するなど、コストのかかる初期化タスクを実行する場合があります。 この場合は、最初の実行中に状態情報をキャッシュし、保存された状態を 2 回目の実行中に再利用します。
Blazor コンポーネントが使用するすべての依存関係は、インスタンスが作成された後、 OnInitialized または OnInitializedAsync メソッドが実行される前に挿入されます。 これらの依存関係によって挿入されたオブジェクトは OnInitialized または OnInitializedAsync メソッドで使用できますが、その前には使用できません。
Important
Blazor コンポーネントでは、コンストラクターの依存関係の挿入がサポートされていません。 代わりに、コンポーネント マークアップで @inject ディレクティブを使用するか、プロパティ宣言で InjectAttribute を使用します。
プリレンダリング フェーズ中に、Blazor Server コンポーネント内のコードで、ブラウザーへの接続が必要なアクション (JavaScript コードの呼び出しなど) を実行することはできません。 ブラウザーとの接続に依存するロジックは、OnAfterRender または OnAfterRenderAsync メソッドに配置する必要があります。
OnParametersSet および OnParametersSetAsync メソッド
OnParametersSet および OnParametersSetAsync メソッドは、コンポーネントが初めてレンダリングされる場合は OnInitialized メソッドまたは OnInitializedAsync メソッドの後に、それ以降にレンダリングされる場合は SetParametersAsync メソッドの後に実行されます。
SetParametersAsync と同様に、これらのメソッドは、コンポーネントにパラメーターがない場合でも常に呼び出されます。
いずれかのメソッドを使用して、コンポーネント パラメーター値に依存する初期化タスク (計算されるプロパティの値の計算など) を完了します。 コンストラクターでは、このような実行時間の長い操作を行わないでください。 コンストラクターは同期的であるため、実行時間の長い操作の完了を待っていると、そのコンポーネントを含むページの応答性に影響を与えます。
OnAfterRender および OnAfterRenderAsync メソッド
OnAfterRender メソッドと OnAfterRenderAsync メソッドは、Blazor ランタイムで、ユーザー インターフェイスのコンポーネントによって表されるビューの更新が必要になるたびに実行されます。 この状態は、次の場合に自動的に発生します。
- コンポーネントの状態が変化する (たとえば、
OnInitializedまたはOnInitializedAsyncメソッドあるいはOnParametersSetおよびOnParametersSetAsyncメソッドが実行されたとき)。 - UI イベントがトリガーされる。
- アプリケーション コードでこのコンポーネントの
StateHasChangedメソッドを呼び出す。
外部イベント、UI トリガーのいずれかから StateHasChanged が呼び出されると、コンポーネントは条件付きで再レンダリングされます。 次の一覧では、StateHasChanged とその後に続くメソッド呼び出しの順序を詳しく説明しています。
- StateHasChanged: コンポーネントを再レンダリングする必要があるものとしてマークします。
- ShouldRender: コンポーネントをレンダリングする必要があるかどうかを示すフラグを返します。
- BuildRenderTree: コンポーネントをレンダリングします。
StateHasChanged メソッドでは、このコンポーネントの ShouldRender メソッドを呼び出します。 このメソッドの目的は、状態の変更によってコンポーネントでのビューのレンダリングが必要になったかどうかを判定することです。 既定では、すべての状態変更でレンダリング操作がトリガーされますが、ShouldRender メソッドをオーバーライドして意思決定ロジックを定義することができます。
ShouldRender メソッドは、ビューを再びレンダリングする必要がある場合は true を、それ以外の場合は false を返します。
コンポーネントをレンダリングする必要がある場合は、 BuildRenderTree メソッドを使用して、ブラウザーが UI の表示に使用する DOM のバージョンを更新できるモデルを生成できます。
ComponentBase クラスによって提供される既定のメソッド実装を使用するか、または固有の要件がある場合はカスタム ロジックでそれをオーバーライドできます。
次に、コンポーネント ビューがレンダリングされ、UI が更新されます。 最後に、このコンポーネントでは OnAfterRender および OnAfterRenderAsync メソッドを実行します。 この時点では、UI が完全に機能しており、JavaScript や DOM 内のすべての要素を操作できます。 これらのメソッドを使用して、JS 相互運用から JavaScript コードを呼び出すなどの、完全にレンダリングされたコンテンツへのアクセスを必要とするその他のすべての手順を実行します。
OnAfterRender および OnAfterRenderAsync メソッドは、firstRender という名前のブール値のパラメーターを受け取ります。 このパラメーターは、そのメソッドが初めて実行されるときは true ですが、それ以降は false です。 コンポーネントがレンダリングされるたびに繰り返す場合、このパラメーターを評価して、無駄でリソースを大量に消費する可能性がある 1 回限りの操作を実行できます。
Note
プリレンダリングを Blazor コンポーネントの最初のレンダリングと混同しないでください。 プリレンダリングは、ブラウザーとの SignalR 接続が確立される前に発生し、ページの静的バージョンを生成します。 最初のレンダリングは、ブラウザーとの接続が完全にアクティブであり、すべての機能が使用可能なときに発生します。
Dispose および DisposeAsync メソッド
他のすべての .NET クラスと同様に、Blazor コンポーネントではマネージド リソースとアンマネージ リソースを使用できます。 マネージド リソースは、ランタイムによって自動的に再利用されます。 しかし、アンマネージ リソースを解放するには、IDisposable または IAsyncDisposable インターフェイスを実装し、Dispose または DisposeAsync メソッドを提供する必要があります。 この方法により、サーバー内でのメモリ リークの可能性が低下します。
ライフサイクル メソッドで例外を処理する
Blazor コンポーネントのライフサイクル メソッドは、失敗するとブラウザーへの SignalR 接続を閉じ、それによって Blazor アプリの機能が停止されます。 この結果を防ぐには、ライフサイクル メソッドのロジックの一部として、例外を処理する準備をするようにしてください。 詳細については、「ASP.NET Core Blazor アプリのエラーを処理する」を参照してください。