値が使用できないため、必須の信号入力はコンストラクターまたはフィールド初期化子で使用できません。値にアクセスするための私の解決策は、実際のシグナルの変更を監視し、サーバーに対して HTTP リクエストを作成し、シグナルの値を設定することです。このエフェクトを使用しないことについては多くの議論があり、それを削除するための他の解決策を見つけなければなりません。
必要な信号入力は、ngOnInit および ngOnChanges ライフサイクル メソッドでアクセスできます。ただし、それらは注入コンテキストの外にあるため、toSignal はエラーをスローします。これは 2 つの方法で修正できます:
import { Component, effect, inject, Injector, input, signal } from '@angular/core'; import { getPerson, Person } from './star-war.api'; import { StarWarPersonComponent } from './star-war-person.component'; @Component({ selector: 'app-star-war', standalone: true, imports: [StarWarPersonComponent], template: ` <p>Jedi Id: {{ jedi() }}</p> <app-star-war-person [person]="fighter()" kind="Jedi Fighter" />`, }) export class StarWarComponent { // required signal input jedi = input.required<number>(); injector = inject(Injector); fighter = signal<Person | undefined>(undefined); constructor() { effect((OnCleanup) => { const sub = getPerson(this.jedi(), this.injector) .subscribe((result) => this.fighter.set(result)); OnCleanup(() => sub.unsubscribe()); }); } }
コードの変更は次のとおりです:
export type Person = { name: string; height: string; mass: string; hair_color: string; skin_color: string; eye_color: string; gender: string; films: string[]; }
import { HttpClient } from "@angular/common/http"; import { inject, Injectable } from "@angular/core"; import { catchError, Observable, of, tap } from "rxjs"; import { Person } from "./person.type"; const URL = 'https://swapi.dev/api/people'; @Injectable({ providedIn: 'root' }) export class StarWarService { private readonly http = inject(HttpClient); getData(id: number): Observable<Person | undefined> { return this.http.get<Person>(`${URL}/${id}`).pipe( tap((data) => console.log('data', data)), catchError((err) => { console.error(err); return of(undefined); })); } }
getData メソッドを使用して StarWarService を作成し、StarWar API を呼び出して人物を取得します。結果は、人または未定義の Observable です。
import { Component, input } from '@angular/core'; @Component({ selector: 'app-star-war', standalone: true, template: ` <p>Jedi Id: {{ jedi() }}</p> <p>Sith Id: {{ sith() }}</p> `, }) export class StarWarComponent implements OnInit { // required signal input jedi = input.required<number>(); // required signal input sith = input.required<number>(); ngOnInit(): void {} }
jedi と Sith は両方とも必須の信号入力です。したがって、コンストラクターでそれらを使用したり、フィールドを初期化するサービスで toSignal を呼び出したりすることはできません。
OnInit インターフェイスを実装し、ngOnInit メソッドで両方の信号入力にアクセスします。
import { Component, VERSION } from '@angular/core'; import { StarWarComponent } from './star-war.component'; @Component({ selector: 'app-root', standalone: true, imports: [StarWarComponent], template: ` <app-star-war [jedi]="1" [sith]="4" /> <app-star-war [jedi]="10" [sith]="44" />`, }) export class App {}
App コンポーネントには StarWarComponent の 2 つのインスタンスがあります。 最初のインスタンスの jedi ID は 1、2 番目のインスタンスの ID は 10 です。インスタンスのシス ID はそれぞれ 4 と 44 です。
export class StarWarComponent implements OnInit { // required signal input jedi = input.required<number>(); starWarService = inject(StarWarService); injector = inject(Injector); light!: Signal<Person | undefined>; }
StarWarComponent コンポーネントに、StarWarService とコンポーネントのインジェクターを挿入します。さらに、toSignal 関数から返された結果を格納するためのライト Signal を宣言します。
interface ToSignalOptions<T> { initialValue?: unknown; requireSync?: boolean; injector?: Injector; manualCleanup?: boolean; rejectErrors?: boolean; equal?: ValueEqualityFn<T>; }
ToSignalOptions オプションにはインジェクター プロパティがあります。インジェクションコンテキストの外で toSignal 関数を使用する場合、コンポーネントのインジェクターをオプションに渡すことができます。
export class StarWarComponent implements OnInit { // required signal input jedi = input.required<number>(); starWarService = inject(StarWarService); injector = inject(Injector); light!: Signal<Person | undefined>; ngOnInit(): void { this.light = toSignal(this.starWarService.getData(this.jedi()), { injector: this.injector }); } }
ngOnInit メソッドでは、サービスを呼び出して Observable を取得し、toSignal 関数を使用してシグナルを作成します。 2 番目の引数は、コンポーネントのインジェクターのオプションです。
<app-star-war-person [person]="light()" kind="Jedi Fighter" />
次に、光信号を StarWarPersonComponent コンポーネントに渡して、ジェダイ戦闘機の詳細を表示します。
export class StarWarComponent implements OnInit { // required signal input sith = input.required<number>(); starWarService = inject(StarWarService); injector = inject(Injector); evil!: Signal<Person | undefined>; ngOnInit(): void { // this also works runInInjectionContext(this.injector, () => { this.evil = toSignal(this.starWarService.getData(this.sith())); }) } }
toSignal 関数から返された結果を保存するために邪悪な Signal を宣言します。 runInInjectionContext の最初の引数はコンポーネントのインジェクターです。 2 番目の引数は、toSignal 関数を実行し、人物を evil 変数に割り当てるコールバック関数です。
<app-star-war-person [person]="evil()" kind="Sith Lord" />
次に、邪悪なシグナルを StarWarPersonComponent コンポーネントに渡して、シス卿の詳細を表示します。
コンポーネントに必要な信号入力がある場合、ngOnInit または ngOnChanges の値にアクセスして、HTTP リクエストやその他の操作を行うことができます。 そうすれば、必要なシグナルを監視してバックエンドを呼び出すためのエフェクトを作成する必要がなくなります。
これでアイアンマン チャレンジ 33 日目は終了です。
参考文献:
以上が外部コンテキスト挿入エラーを回避するために手動インジェクターを toSignal 関数に渡しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。