Angular v17.1.0にて、Signal Inputsという機能がリリースされる見込みだ。Signals APIのRFC段階から提案されていたものだが、ついに実際に使えるAPIになる。この記事ではSignal Inputsによって何が変わるのかをかいつまんで解説する。
Signal Inputsとは
Signal InputsはSignals RFCの中でもSignal-based Componentsのセクションで提案されている。
In signal-based components, all component inputs are signals.
ここで書かれているように、コンポーネントのインプットプロパティをSignalとして宣言できる。従来のSignalではないオブジェクトでは、インプットの変更に反応して処理をおこなうために ngOnChanges
ライフサイクルフックや、setterによる代入処理への割り込みが必要だったが、Signal Inputsでは通常のSignalと同様にcomputed
やeffect
によってリアクティブな処理ができる。
例
以下は実際に動作するサンプルコードだ。input()
によってインプットプロパティを宣言している。親コンポーネントから値を必ず受け取りたい場合はinput.required()
で指定できる。コンポーネント内ではSignalとして扱えるため、インプットの値が変わったときに行いたい処理はeffect
を使う。
Signal Inputsで何が変わるのか
Signal Inputsへの移行により、特に以下の3つの点が大きく変わると考えられる。
ngOnChanges
が不要になる
これまではどのインプットが更新されても単一のngOnChanges
ライフサイクルフックで待ち受けるか、あるいはsetterを使うしかなかったが、それらはSignal Inputsとeffect
で一切不要になる。setterで入力された値の前処理をしていたようなケースも、今はすでにInput Transformもあるため、インプットプロパティのsetterが必要なケースは皆無だろう。
TypeScriptのstrictPropertyInitialization
を常に有効化できる
TypeScriptのstrictモードに含まれているstrictPropertyInitialization
は、クラスプロパティが必ず初期化されていることをチェックする設定だが、親から値を受け取ることを前提にしたコンポーネントではインプットプロパティに初期値を入れられず、strictPropertyInitialization
フラグをオフにしなければならないケースがあった。このことについては以前に記事を書いている。
Signal InputsによってすべてのインプットプロパティはSignal型のオブジェクトで初期化されることになるため、この記事で書いたベストプラクティスはすべて過去のものとなる。strictPropertyInitialization
は常に有効化できるようになるはずだ。
インプットがイミュータブルになる
input()
によって作成されるInputSignal
オブジェクトは、computed
と同じく読み取り専用のSignalである。これまではプリミティブ型ではないミュータブルなオブジェクトがインプットプロパティに渡された場合、子コンポーネントから親コンポーネントへ変更が逆流することがありえた。Signal Inputsであればそのようなことはなくなり、バグが起きにくくなる。