2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Blazor Web App 入門メモ:React経験者の視点で構成とルーティングを整理してみた

2
Posted at

Blazor を触り始めたので、まずは公式チュートリアルを進めながら、

  • このファイルは何をしているのか
  • React でいうと何に近いのか
  • 画面はどうやって切り替わるのか

を自分なりに整理してみました。

今回は主に、以下の観点で見ています。

  • Program.cs は何をしているのか
  • App.razorRoutes.razor の役割
  • Pages 配下の .razor ファイルがどうルーティングされるのか
  • @rendermode InteractiveServer は何を意味するのか

まず全体像

Blazor Web App では、.razor コンポーネントを中心に画面を構成します。

最初に触ってみて感じたのは、React の感覚で見ても対応関係を作りやすい ということでした。

ざっくり対応を並べるとこんな感じです。

React Blazor
index.js + App コンポーネント App.razor
BrowserRouter + Routes Routes.razor
<Route path="/" element={<Home />} /> @page "/"
<Outlet /> に子ルートを表示 RouteView で対象コンポーネントを描画
共通レイアウトコンポーネント MainLayout.razor

もちろん完全に同じではありませんが、
「アプリ全体の入口」「ルーティング」「各ページコンポーネント」 という見方をすると理解しやすかったです。


Program.cs はアプリの起動地点

Program.cs は、Blazor Web App の起動設定を行う場所です。

React でいう「画面そのもの」ではなく、
どちらかというと アプリケーションの初期設定・サービス登録・起動処理 を担うエントリーポイントです。

ここで例えば、

  • アプリを起動する
  • 必要なサービスをDIコンテナに登録する
  • Razor Components を有効化する
  • Interactive Server などの実行モードを有効化する

といった設定を行います。

そのため、Program.cs
フロントエンドのエントリーポイントというより、ASP.NET Core アプリの起動設定 と捉えたほうが自然でした。


App.razor はアプリ全体の土台

App.razor は、アプリ全体のHTMLの土台を持つファイルです。

チュートリアル直後の構成では、例えば以下のようになっています。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="@Assets["lib/bootstrap/dist/css/bootstrap.min.css"]" />
    <link rel="stylesheet" href="@Assets["app.css"]" />
    <link rel="stylesheet" href="@Assets["BlazorApp_Web_Test.styles.css"]" />
    <ImportMap />
    <link rel="icon" type="image/png" href="favicon.png" />
    <HeadOutlet />
</head>

<body>
    <Routes />
    <script src="_framework/blazor.web.js"></script>
</body>

</html>

ここで重要なのは、<Routes /> が置かれていることです。

つまり App.razor は、

  • HTMLのベースを定義し
  • スタイルやスクリプトを読み込み
  • 実際のページ切り替えは Routes に委ねる

という役割を持っています。

Reactでいうと、index.htmlApp の役割が少し混ざったような印象を受けました。


Routes.razor がルーティングを担う

ルーティングの中心になるのが Routes.razor です。

<Router AppAssembly="typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />
        <FocusOnNavigate RouteData="routeData" Selector="h1" />
    </Found>
</Router>

このコードを見て理解したことは次の通りです。

Router

現在のURLに応じて、どのコンポーネントを表示するかを判断します。

RouteView

URLに対応するコンポーネントを描画します。
さらに DefaultLayout を指定することで、共通レイアウトの中に各ページを埋め込めます。

FocusOnNavigate

ページ遷移時に指定した要素へフォーカスを移します。
ここでは h1 にフォーカスするようになっており、アクセシビリティ向上のための仕組みです。


Pages 配下の .razor がページになる

Pages ディレクトリには、画面として扱われる .razor ファイルが置かれます。

例えば Counter.razor に以下のような記述があるとします。

@page "/counter"
@rendermode InteractiveServer

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

このとき /counter にアクセスすると、この Counter.razor が表示されます。

ポイントは、ルーティング定義を中央でまとめて書くというより、各ページ側で @page を宣言する ことです。

最初は少し不思議に感じましたが、
「このコンポーネントはこのURLを担当する」とページ自身が宣言している、と考えると分かりやすかったです。


@rendermode InteractiveServer とは何か

このコードで特に気になったのが @rendermode InteractiveServer でした。

@rendermode InteractiveServer

これは、そのコンポーネントを Interactive Server モード で動かす指定です。

このモードでは、UIイベントはサーバー側で処理され、
ブラウザとはリアルタイム接続を通じてやり取りされます。

たとえばボタンをクリックすると、

  1. ブラウザでクリックイベントが発生する
  2. サーバー側のコンポーネントにイベントが送られる
  3. サーバー側で状態が更新される
  4. 差分がブラウザに反映される

という流れで動きます。

そのため、見た目はSPAっぽく動きますが、
処理の主体はサーバー側にある のが特徴です。


@onclick は Blazor のイベントバインディング

この部分はかなり直感的でした。

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

React の onClick に近い感覚で読めます。

クリック時に IncrementCount メソッドが呼ばれ、
その中で currentCount を更新すると、画面が再描画されます。

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

「状態を変えたらUIに反映される」という意味では React とかなり似ていますが、
Blazor では C# のメソッドをそのままイベントハンドラとして書けるのが面白いところです。


親から子へ値を渡すには [Parameter]

Blazor コンポーネント間で値を渡すときは、[Parameter] 属性を使います。

子コンポーネント側はこんな形です。

@page "/counter"
@rendermode InteractiveServer

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    [Parameter]
    public int IncrementAmount { get; set; } = 1;

    private void IncrementCount()
    {
        currentCount += IncrementAmount;
    }
}

親コンポーネント側はこんな形です。

@page "/"

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.
<br />
<br />
<Counter IncrementAmount="5" />
<br />
<br />
<Weather />

React の props に近い考え方ですが、
C# のプロパティとして受け取るのが特徴です。


開発中の実行は dotnet watch

開発中は dotnet watch を使うと変更を監視しながら実行できます。

React の npm start や Vite の開発サーバーの感覚に近く、
修正しながら動作確認しやすいです。


触ってみて感じたこと

Blazor Web App を最初に触ってみて、個人的には次のように整理できました。

  • Program.cs はアプリ起動と設定
  • App.razor は全体の土台
  • Routes.razor がルーティングの中心
  • Pages 配下の .razor が実際のページ
  • @page でURLを担当する
  • @rendermode で実行モードを切り替える
  • @onclick[Parameter] など、コンポーネント指向の書き味がある

React経験者として見ると、完全に同じではないものの、
「どこが対応しているか」を掴みながら進めると理解しやすい と感じました。

次は、InteractiveServerInteractiveWebAssembly の違いや、
Blazor Web App と Blazor WebAssembly の関係も整理してみたいです。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?