本レクチャーでは、計測画面(MeasurePage.razor)を題材に、OnInitializedが2回実行されてしまう問題と、その対応方法を解説します。
まず、OnInitializedメソッドにブレークポイントを設置した状態でアプリを実行し、サイドメニューの「計測」から計測画面を表示します。
図1 OnInitializedにブレークポイントを設置
ブレークポイントで処理が止まったところで「続行」を押すと、もう1回同じブレークポイントで止まります。1回の画面表示で2回ブレークポイントにヒットしていることになります。
図2 「続行」を押すと再びOnInitializedで停止する
念のためHomeを押してから改めて計測画面を開き、F10でステップ実行しながら続行しても、同様にもう1回OnInitializedを通ることが確認できます。
図3 F10でのステップ実行時も同様に2回目のヒットが発生
なぜ2回通ってしまうのかというと、以前のレクチャーでユーザー操作を行う画面には記述しておくよう案内した @rendermode InteractiveServer が原因です。この記述があると、Blazorの「プリレンダリング」という仕組みが働きます。
プリレンダリングとは、ユーザーに画面をすばやく表示するため、サーバー側であらかじめHTMLを生成しておく仕組みです。このプリレンダリングの際に1回OnInitializedが実行され、さらにクライアント側がサーバーと通信して実際にブラウザへ画面を表示する際にもう1回OnInitializedが実行されるため、結果として2回実行されることになります。
この現象については、Stack Overflowでも同様の質問と回答がされています。
図4 Stack Overflowに投稿されている同様の質問(URLはボーナスレクチャーを参照)
回答では、@rendermode InteractiveServer を、プリレンダリングを無効にした @rendermode @(new InteractiveServerRenderMode(prerender: false)) という記述に置き換えることが対応方法として示されています。
図5 Stack Overflowの回答に示されている置き換え後の記述
この対応をMeasurePage.razorに反映します。まず、既存の @rendermode InteractiveServer の行をコメントアウトします。
@* @rendermode InteractiveServer *@
続けてその下に、prerenderをfalseに指定した新しい @rendermode の記述を追加します。デフォルトではprerenderはtrueになっており、これがプリレンダリングが有効になっている原因です。それをfalseにすることでプリレンダリングをオフにします。
図6 新しい@rendermodeの記述を入力しているところ
@rendermode @(new InteractiveServerRenderMode(prerender: false))
図7 入力し終えた@rendermodeの記述(prerender: falseを指定)
図8 MeasurePage.razor冒頭の最終的な記述内容
この状態で実行し、計測画面を開いてボタンを押すと、OnInitializedは1回しか通らなくなります。
図9 修正後、計測画面が正しく表示される
なお、OnInitializedが2回通ってしまうこと自体は、今回のようにメモリ上の値をセットしているだけの処理であれば、特に問題にならないことも多いです。しかし、ここでデータベースの検索など負荷の高い処理を行っている場合は、無駄に2回実行されてしまい、パフォーマンス上好ましくありません。そのため、そうした処理を行う画面では、プリレンダリングをオフにする対応をしておいた方がよいでしょう。
プリレンダリングをオフにしても大丈夫かという点については、プリレンダリングはあくまで「サーバー側であらかじめHTMLを作っておくことで、ほんの少し表示を早くする」ためのものであり、オフにしたからといって画面表示が体感できるほど遅くなることはほとんどありません。気になる場合は実際に試してみて、パフォーマンスに影響があるようであれば、そのときに改めて調整すればよいでしょう。
基本的には、ユーザー操作を伴う画面ではこの @rendermode @(new InteractiveServerRenderMode(prerender: false)) を記述しておくのがおすすめです。なお、今回解説したOnInitializedだけでなく、パラメータ変化時に呼ばれるOnParametersSetについても同様に2回実行されてしまう現象が起きるため、あわせて1回に抑えるようにしておくとよいでしょう。
A01_はじめに
A02_バージョンの確認
A03_プロジェクトの作成
A04_アプリの実行
A05_サンプルプログラムの構成
A06_Razorコンポーネント
A07_Razor構文
A08_@pageでURLを指定する
A09_@rendermode
A10_PageTitle
A11_HTMLの見出し
A12_pタグ
A13_単方向データバインド
A14_単方向データバインドの詳細
A15_Bootstrap
A16_ボタンクリックイベント
A17_イベント引数の受け取り方
A18_ここまでのまとめ
B01_新しいWebページを追加する方法
B02_サイドバーから画面を表示する
B03_サイドバーのアイコンを変更する方法
B04_計測値を表示する
B05_変数に置き換える
B06_最新の値でデータを更新する
B07_@usingで通常のC#コードを呼び出す
B08_画面遷移_aタグ
B09_画面遷移_aタグの見た目をボタンにする
B10_画面遷移_NavigationManagerでの遷移
B11_画面間のパラメータの受け渡し方法
B12_EscapeDataStringでエスケープする
B13_複数のパラメータを渡す
B14_任意のパラメータにする
B15_string以外の型をパラメータで使う方法
B16_DateTime型をパラメータで渡す方法
B17_引数2個のURLも型指定に変更する
B18_パラメータ属性をつけるときの注意点
B19_OnParametersSet
B20_OnInitialized
B21_OnInitializedが2回通る問題の対応
B22_ブラウザが開いている間の値を記憶する方法
B23_値の受け渡しとしてのProtectedSessionStorage
B24_非同期を想定したUIの制御
C01_一覧表示
C02_非同期での一覧表示
C03_table-striped
D01_入力エリア
D02_双方向データバインド
D03_入力データをリアルタイムで通知する方法
D04_placeholder
D05_入力エリアの横幅の調整
D06_テキストチェンジイベントを拾う方法
D07_プルダウン
D08_プルダウンのbootstrap
D09_プルダウンの選択している値をデータバインドで操作する
D10_プルダウンにリストの値を表示する
D11_プルダウンに未選択行を入れる
D12_プルダウンの入力を禁止する
D13_プルダウンのチェンジイベントを取得する
D14_チェックボックス
D15_チェックボックスにラベルを付ける
D16_複数のチェックボックスを並べる
D17_ラジオボタン
D18_ラジオボタンのデータバインド
D19_ラジオボタンのチェンジイベント
D20_ラジオボタンにbootstrapを適応する