Итак, я новичок в сигналах и пытаюсь использовать их все больше и больше в нашем приложении. Часть, которую я до сих пор не могу уяснить, — это связь между rxJS и Signals. Поскольку мы используем HTTP-клиент Angulars, нам приходится иметь дело с наблюдаемыми (что неплохо). Но теперь я пытаюсь сделать свой код более реактивным, обновляя значение сигналов, выполняя вызов API всякий раз, когда изменяется идентификатор объекта с ограниченной областью действия (который сам является сигналом). Вот что я придумал:
effect(() => {
this.apiService.hasSomething({
customerId: mySignalWhoseValueChanges()
}).subscribe(value => this.mySignal.set(value));
});
Если я использую mySignal() в своем шаблоне и изменяю mySignalWhoseValueChanges(), он вызовет effect(), потому что effect() прослушивает любые изменения сигналов, которые используются внутри него.
Дело в том, что я на 100% уверен, что есть лучший подход без использования effect(), но я просто не знаю. Я пробовал использовать toSignal(), но это не работает, поскольку на самом деле это не сигнал, на который ссылаются, а только значение на момент его создания, или я что-то упускаю:
this.mySignal = toSignal(this.apiService.hasSomething({
customerId: mySignalWhoseValueChanges()
}))
Заранее спасибо!





Вы можете довольно легко объединить сигнал с http-запросом.
Вы можете использовать функцию toObservable для отслеживания изменений в сигнале, а затем запускать HTTP-запрос при изменении идентификатора.
Примечание. Сигналы НЕ предназначены для замены RxJS (по крайней мере, в ближайшее время). Они предназначены для работы в унисон.
Для этого вам следует предпринять следующие шаги:
user для наблюдения за текущим пользователем. (это может быть что угодно, я выбрал номер).response для отслеживания ответа http.user.toObservable и передайте свой сигнал user в качестве параметра.response данными.import { toObservable } from '@angular/core/rxjs-interop';
@Component({
selector: 'app-root',
standalone: true,
imports: [HttpClientModule, FormsModule, AsyncPipe, JsonPipe],
styles: ['div{font-family: monospace}'],
template: `
@if ({request: page$ | async}) {
<div>{{response() | json}}</div>
}
<p>Enter a number from 1 to 4.</p>
<input [(ngModel)] = "user" />
`,
})
export class App {
user = signal<number>(0); // A way to watch users
response = signal<any>(undefined); // A way to watch for http changes
constructor(private readonly http: HttpClient) {}
page$ = toObservable<number>(this.user).pipe( // Watch for user changes
filter((id) => id > 0), // Only make http request for users larger than 0
tap((id) => console.info('user id', id)), // Just some debugging
exhaustMap((id) => // Don't execute the http request if one is already in progress
this.http
.get<Response>(`https://example.com/user/${id}`) // Make the http request
.pipe(tap((response) => this.response.set(response))) // Update the response
)
);
}
При вашем подходе запрос будет выполнен только один раз. если бы вы, например, указали example.com/endpoint/customerId в качестве URL-адреса, даже если customerId обновится (что в моем случае является сигналом), запрос не будет выполнен снова, или я упускаю суть?
@MartinHochmair Похоже, мой последний комментарий об обновлении ответа не сохранился... Но в любом случае я обновил ответ, который должен учитывать ваш комментарий.
Спасибо, это было то, что я искал! Я надеялся на простой подход, но это определенно лучше, чем эффект.
Использование гораздо более чистого подхода к получению запросов на основе идентификатора объекта.
На момент написания предпочтительнее сохранить компоненты службы как операторы rxjs и использовать сигналы для синхронной реактивности.
Эффекты в настоящее время используются только для рендеринга изменений в представлении, а не в бизнес-логике (вы можете сделать это, используя untracked()).
Подробнее об этом можно узнать здесь.
import { toObservable, toSignal } from '@angular/core/rxjs-interop';
entityId = input.required<string>({
alias: 'id',
});
response = toSignal(
toObservable<string>(entityId).pipe(switchMap((id) => this.apiService.fetchById(id))),
);
Я не думаю, что рекомендуется использовать «эффект» в ответах HTTP. Они рекомендуют это только в некоторых ситуациях angular.io/guide/signals#use-cases-for-effects . Так что придерживайтесь традиционного развития, с моей точки зрения.