我是使用可观察量的新手,并且开始学习声明式编程。我遇到的情况是,我有一个可观察对象从 http 请求获取数据。我知道可以使用地图运算符对这些数据进行排序。
我不明白的是,如果我想根据按钮单击对这些数据进行排序(因此在http请求完成后)我怎样才能做到这一点而不需要observable再次调用http请求。我知道我可以将数据放入数组中并对其进行排序,但是是否可以仅使用可观察量/主题/行为主题等来做到这一点。
我确信这很简单,但由于我刚刚开始使用可观察值,我发现这有点令人困惑。
希望有人能指出我正确的方向。
热烈的问候
我想你应该将你的http服务的响应保存为组件类属性,然后根据需要使用它。
它应该类似于:
// .ts
myData: MyDataInterface[];
ngOnInit() {
this.httpService.getMyData()
.subscribe(response => this.myData = response);
}
onButtonClick() {
this.sortMyData();
}
sortMyData() {
this.myData = /** do sorting*/;
}
// .html
<button (click)="onButtonClick()">Sort my data</button>
但是仅使用可观察量/主题/行为主题等就可以做到这一点吗?
是的。
由于您没有提供示例,我将进行一些假设。
假设您在 Angular 的 Init 生命周期上运行 HTTP-GET。 然后您订阅传入的响应,以对其执行某些操作。 然后,根据“按钮被单击状态”,您希望触发订阅而不触发请求,因此将排序应用于“缓存”响应。
一种方法是“mergeMap”:https://rxjs.dev/api/operators/mergeMap
@Component({
selector: 'app-root',
standalone: true,
template: `
<h1>Hello from {{ name }}!</h1>
<div>
<button (click)="sort($event)"> sort</button>
</div>
`,
})
export class App implements OnInit {
public $sortEvent = new BehaviorSubject<boolean>(false); // holds the current sort state event,
name = 'Angular';
ngOnInit(): void {
this.fetchSomeData() // this will only be called once
.pipe(
// here you merge the data of the fetch
// and declare that you want to use the data in a new observable
// this new observable is the sortEvent
// lis: is now a state within this construct, the observable before will not be triggered again
mergeMap((lis) =>
this.$sortEvent.pipe(map((isSorted) => (isSorted ? [...lis].sort() : lis)))
)
)
.subscribe((e) => {
// this will be triggered
// only on the initial fetch
// and then only when $sortEvent emits a value
console.log(e);
});
}
sort(event: Event) {
this.$sortEvent.next(true);
}
// this mocks a http request
fetchSomeData(): Observable<number[]> {
return of([8, 2, 4, 1, 6, 1, 0]).pipe(
tap(() => console.log('do I have been called?'))
);
}
}
这里需要注意的是,需要正确清理订阅。
意见建议: 尽管 Observables 和管道是处理复杂异步值的好工具,但它经常被低估,维护 mergeMaps 和 switchMaps 有多困难,以及使用这些方法创建内存泄漏的频率有多高且未被注意到。
如果 a 的值无论如何都不会改变,则应仔细考虑:
我真的需要这个东西成为可观察的吗?
我举个例子。您请求一份清单。 如果值尚未到达,则无论如何都不会显示或渲染组件。 但是您希望根据可观察到的内容显示列表,实际上该列表经常发生变化,并且当它发生变化时,应该重新渲染某些内容。
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule],
template: `
<h1>Hello from {{ name }}!</h1>
<div>
<button (click)="sort($event)"> sort</button>
<div>{{$maybeSortedList | async}}</div> // use the async pipe to listen to the changing arrangements of the list
<div>{{list }}</div>
</div>
`,
})
export class App implements OnInit {
name = 'Angular';
private $isSorted = new BehaviorSubject(false); // have a observable for a changing object
public list: number[] = []; // have no observable for a object that changes only on init
public $maybeSortedList = this.$isSorted.pipe(
map((isSorted) => (isSorted ? [...this.list].sort() : this.list)), // map it to the list
);
ngOnInit(): void {
this.fetchSomeData().subscribe((response) => {
this.list = response;
});
}
sort(event: Event) {
this.$isSorted.next(true);
}
fetchSomeData(): Observable<number[]> {
return of([8, 2, 4, 1, 6, 1, 0]).pipe(
tap(() => console.log('do I have been called?'))
);
}
}
使用可观察对象。但不要合并、平面图、切换图超出所需范围。