6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

.NET 7 の新機能 @bind:after で input 入力を即時処理する (そしてもう一度死ぬ)

Posted at

Blazor で input 入力をフィールド変数にバインドしつつ即時処理する実装に納得感が薄い...

2年前にこんな記事を書きました。

"Blazor 開発者は input 入力を即時処理しようとして二度死ぬ"

どういうことかと言うと、Blazor で input 入力をフィールド変数にバインドしつつ、入力イベントで即時にそれを処理したい場合、

  • @bind 構文と、@oninput イベントハンドラを一緒に使うとビルドエラーで使わせてくれない
  • なので、@bind 構文は使わずに、value="@..." で単方向バインドにしつつ、@oninpt イベントハンドラで自分でフィールド変数を更新する必要がある

というお話でした。「input 入力をフィールド変数にバインドして、即時ページ上に表示しつつ、入力イベントで即時に console.log に入力内容を出力」という Blazor コンポーネントの実装例を下記に記します。

*.razor
<!-- 👇oninput イベントを捕捉すると、ここで "@bind" 構文が使えない -->
<p><input value="@_CurrentValue" @oninput="OnInput" /></p>

<p>CurrentValue is: "@_CurrentValue"</p>

@code {
  private string? _CurrentValue = "Initial Value";

  private void OnInput(ChangeEventArgs e)
  {
    // 👇 @bind による双方向バインドができないため、
    //    入力イベントハンドラ内で自分でフィールド変数を更新する必要がある😥
    _CurrentValue = e.Value as string;

    Console.WriteLine($"OnInput: \"{_CurrentValue}\"");
  }
}

React のように単方向バインドが基本のフレームワークに慣れていれば、上記のような "制約" は、制約でもなんでもなくて普通で自然なことに感じられると思います。むしろ双方向バインドは邪悪とされているかもしれませんね、いっぽうで、Angular のように双方向バインドが可能なフレームワークに慣れていると、双方向バインド構文とイベント捕捉が競合してしまい、双方向バインドは使えない、というのは釈然としないものがあります。自分のような、"書くべきコードが少ないってのが、本当に良い" "Write less code こそがやはり真理なんや" という派 (出典: "最近のフロントエンドフレームワークに対する認識とお気持ちの整理 | console.lealog();") としては、結構、こういう些細なことでもやったりします。(だったら Svelte やれば? みたいな話になるのかもしれませんが、それはちょっと置いておいて。)

@bind:after 新構文で解決!

しかしです!

ついに、2022年11月リリースの .NET 7 から、「双方向バインドしつつ、イベントハンドリングを行なう」をより自然に行なうことができるようになりました! @bind:after という新構文です! 名前から察しがつくと思いますが、@bind による双方向バインドにおいて、入力値がバインド先変数に格納された直後に実行するコールバック関数を設定できるのが、この @bind:after 構文です。冒頭の実装例は、.NET 7 では、@bind:after を使って下記のとおりスッキリ実装できます!

*.razor
<!-- 👇 @oninput じゃなくて、@bind:after を使えば... -->
<p><input @bind:event="oninput" @bind="_CurrentValue" @bind:after="OnInput" /></p>

<p>CurrentValue is: "@_CurrentValue"</p>

@code {
  private string? _CurrentValue = "Initial Value";

  private void OnInput()
  {
    // 👇 入力のたびにここが呼び出されるが、その時点で、
    //     双方向バインドしてあるフィールド変数は更新済み! 直感的!
    Console.WriteLine($"OnInput: \"{_CurrentValue}\"");
  }
}

.NET 7 の公式リリース前、Preview 7 の頃から @bind:after 構文は使えていましたので、下記のように紹介記事もあったりしました。

自分も .NET 7 リリース候補版の段階で、手持ちの Blazor アプリにおいて、@bind:after を使った実装への変更を開始し、開発中ブランチにコミットしておくなど行なっておりました。

そして先月 2022 年 11 月に、ついに .NET 7 が公式リリースとなったわけです。

.NET 7 が 正式リリースしたらビルドすら通らないだと...!?

先月 2022 年 11 月に開催された、Microsoft 主催によるオンラインイベント ".NET Conf 2022" を経て、ついに .NET 7 SDK 正式リリース版がダウンロード可能となりました。自分も程なくこれをダウンロード、インストールして、@bind:after を使った実装への改訂ブランチを main ブランチにマージなど始めました。

ところがです。

そうしてウキウキしながら、.NET 7 SDK 正式リリース版でその Blazor アプリケーションプロジェクトをビルドしたところ、な、なんと、@bind:after を使っている箇所が、CS1503 のビルドエラーになってしまうではありませんか...!

...\Microsoft.NET.Sdk.Razor.SourceGenerators\Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator\App_razor.g.cs(..., ...):
error CS1503: Argument 3: cannot convert from 'Microsoft.AspNetCore.Components.EventCallback' to 'System.Action<string?>'

慌ててネットで検索してみたところ、既に下記 Issue が立てられていました。なんと...。

ということで、.NET 7 の最後のリリース候補版までは使えていた @bind:after 構文が、.NET 7 の正式リリースにともなって、各種コンパイラのビルドプロセスの不具合に起因して、使えなくなってしまった、という顛末です。"リリース候補版" とは一体なんだったのか...。

上記の Issue を見る限り、「.NET SDK 7.0.200 で直るはずだから、それまで待っててー」 ということらしいので、辛抱強く待つしかありませんね!

.NET SDK 7.0.101 で少し直り始めた!

そんな不遇な @bind:after 構文ですが、先日、2022年12月13日にリリースされた .NET 7 SDK のパッチバージョン、v.7.0.101 で、少し改善されました。このバージョンの SDK であれば、@bind:after 構文を使ったコードがビルド成功するようになったのです!

ただ、まだ残念ながらすべてのツール類が更新されたわけではないため、例えば Visual Studio のエディタ上では引き続き CS1503 エラーが表示されます (下図)。

image.png

ただしこの状態でも、前述のとおり、ビルドは成功するようになりました。もちろんそのまま実行もできます。エディタのエラー表示は鬱陶しいものの、とにかくこれで @bind:after 構文を使えるようになりました。

完全にすべてのツールが更新・修正されるまで、おそらくは .NET SDK v.7.0.200 のリリースタイミングということになるのだろうと思いますが、それまでの辛抱です。ASP.NET Core 開発チームの皆さん、期待しております!

6
2
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
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?