[初心者][備忘録]Blazorにおけるルーティングの実装

# はじめに

Blazorでは、ページ間のナビゲーションにルーティングを使います。この記事では、Blazorでの基本的なルーティングについてまとめます。

## ルーティング・ルートパラメーターとは
そもそもの「ルーティング」「ルートパラメーター」についてまとめます。
ルーティングとは、**「どのURLで、どのページを表示するかを決める仕組み」**のことです。

例えば、ブラウザで```http://example.com/about```と入力したときに、**"Aboutページ"**が表示されるように設定するのが「ルーティング」です。この仕組みによって、ユーザーがクリックしたリンクや入力したURLに応じて、適切なページが表示されます。

Blazorでは、ルーティングを使って以下のようなURLを管理します。


```csharp
@page "/about"
```

このコードをBlazorのコンポーネントに書くことで、/aboutというURLにアクセスすると、そのコンポーネントが表示されるようになります。

また、ルートパラメーターとは、変動する部分をURL内に持たせることで、同じページでも異なるデータを表示できるようにするためのものです。
例えば、商品ページ/products/1では商品ID1の商品が、/products/2では商品ID2の商品が表示されるようになります。


## ルートパラメーターの指定方法
Blazorでは、ルートパラメーターはURIの一部として指定します。

例:
```csharp
@page "/product/{id}"

@code {
    [Parameter]
    public int Id { get; set; }
}
```

ここで、`{id}`がルートパラメーターとして定義されています。
`/product/{id}`という形式のURLを使うと、URLの一部である`id`が`Id`プロパティに自動的にセットされます。例えば、`/product/5`というURLにアクセスすると、`Id`プロパティには5がセットされます。

BlazorでURLから値を受け取るためには、プロパティに[Parameter]属性を付与する必要があります。
これは、[こちら](https://qiita.com/minoura_a/items/a2f0c4c2de6e331379f9#%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF-component-parameters)の記事にある、コンポーネントパラメーターの定義方法と同様です。
[MSLearn](https://learn.microsoft.com/en-us/training/modules/use-pages-routing-layouts-control-blazor-navigation/4-explore-route-parameters-effect-apps-routing)によると、Blazorの内部では、Blazorルーターがこのルートパラメーターを取得し、コンポーネントにコンポーネントパラメーターとして渡すそうです。
そのため、コンポーネントパラメーターと同じ方法でルートパラメーターにアクセスできるようになっています。

> Component parameters are values sent from a parent component to a child component. In the parent, you specify the component parameter value as an attribute of the child component's tag. Route parameters are specified differently. They're specified as part of the URI. Behind the scenes, the Blazor router intercepts these values and sends them to the component as component values, which is why you can access them in the same way. Route parameters are case insensitive and are forwarded to a component parameter with the same name.

## パラメーターの省略

ルートパラメーターは必須ではありません。パラメーターを省略可能にする場合、以下のようにパラメータの名前の末尾に`?`をつけることで省略可能にできます。

```csharp
@page "/product/{id?}"
```

このようにすることで、/productのみが指定された場合でも、ページが動作します。

## 型の指定で正確なパラメーターを扱う

Blazorのルーティングでは、正しいURLであれば基本的にどのような値でもパラメーターに指定できます。
しかし、例えば数値を期待しているのに文字列が渡されると、意図しない結果となる場合があります。

そのため、パラメーターの型を指定して、誤った入力を防ぐことができます。

```csharp
@page "/product/{id:int}"
```

これにより、idが整数であることを期待し、もし文字列などが渡された場合はルーティングエラーになります。

## 複数のパラメーターを受け取る方法

Blazorではデフォルトで1つの値しかパラメーターとして受け取れませんが、パラメーターの前に*をつけることで、URIのスラッシュで区切られた全ての値を取得することができます。

```csharp
@page "/categories/{*values}"
```

この場合、URIが`/categories/electronics/phones`のようになっていると、`values`に`"electronics/phones"`がセットされます。

## NavigationManagerを利用する

Blazorでは、ルーティングを管理するためのNavigationManagerというクラスが用意されています。
例えば、ユーザーがアプリケーション内の異なるページ間を移動する際に、URLの変更やページの表示を制御し、画面遷移ができます。

'@inject'の後にNavigationManagerを宣言すれば、そのコンポーネント内で使用することが可能です。
NavigateManagerでページへ遷移する例です。

```csharp
@inject NavigationMaager NavigationManager
@page "/product/{category?}/{id:int?}"

<h3>Product Details</h3>
// 子コンポーネントへURIでもらったパラメータ渡している
<ProductDetails Category="@Category" Id="@Id"></ProductDetails>
<p>
    <button @onclick="ShowOtherCategory">別のカテゴリを表示</button>
</p>

<p>
    <button @onclick="MoveHome">ホームへ移動</button>
</p>

@code {
    [Parameter]
    public string Category { get; set; }

    [Parameter]
    public int Id { get; set; }

    private void ShowOtherCategory()
    {
        // 同じページのパラメータが異なるページ移動している
        NavigationManager.NavigateTo($"/counter/{(Category == "phones" ? "laptops" : "phones")}/{Id}");
    }

    private void MoveHome()
    {
        // 別ページに移動している
        // NavigationManager.BaseUriでベースURIを取得
        // 今回は"/"が指定される
        NavigationManager.NavigateTo(NavigationManager.BaseUri);
    }
}

// ProductDetails.razor
// Product.razorで使用しているコンポーネント
<h4>Product Details</h4>

<p>Category: @Category</p>
<p>ID: @Id</p>

@code {
    [Parameter]
    public string Category { get; set; } = "phones";

    [Parameter]
    public int Id { get; set; } = 0;

    protected override void OnInitialized()
    {
        // 初回のみ呼び出されます
        Console.WriteLine("OnInitialized called");
    }

    protected override void OnParametersSet()
    {
        // パラメーターが変更されるたびに呼び出されます
        Console.WriteLine("OnParametersSet called");
    }
}

// MoveHomeで以下のページに移動
// home.razor
@page "/"

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

```

# まとめ

Blazorのルーティング機能を使うと、URLパラメーターを利用して動的なページナビゲーションが可能です。
@pageディレクティブでルートを定義し、[Parameter]属性を使ってURLパラメーターをコンポーネントに受け渡せます。
NavigationManagerを活用すれば、プログラムからのナビゲーション制御も容易に行えることがわかりました。

## 参考
https://learn.microsoft.com/ja-jp/training/modules/use-pages-routing-layouts-control-blazor-navigation/1-introduction