我对Angular和RxJS还很陌生,很难理解RxJS运算符的某些方面。我这里有一些代码(在一个组件中(:
this.salesService.getOrders().subscribe(orders => {
this.orders = orders;
this.orders.forEach((order, index) => {
this.salesService.getOrderCustomers(order.id).subscribe(customers => {
this.orders[index]['customerName'] = customers.map(c => {return c.name}).join(", ");
})
});
});
这样做的好处是,当在我的模板中的表中使用this.orders
时,它将立即可用,然后随着对getOrderCustomers
服务方法的每次调用完成,包含客户名称的列将填充。
我的问题是,如果用纯RxJS也可以表达,因为上面似乎不是";RxJS方式";,我想学习。此外,为了在NgRx ComponentStore中隔离获取客户的效果,我的理解是,上述方法将不起作用,因为effect
方法必须返回一个可观察的。
我尝试了一些类似的东西:
this.salesService.getOrders().pipe(
mergeMap(response =>
from(response.orders).pipe(
concatMap((oneOrder: object) => {
return this.salesService.getOrderCustomers(oneOrder['id'])
}),
reduce((customers, customer) => [...customers, customer], []),
map(customerList => {
/* ?? Here I would return 'response' with the customer name added into each order,
but I have no indexing of the orders to work with */
})
)
),
我有两个问题——第一,我不知道如何将检索到的客户添加到response.orders
变量的正确位置,第二,在完成所有内部请求之前,外部可观察对象似乎不会发出。有没有任何RxJS方法可以从内部可观测逐渐改变外部可观测,同时最初以其原始状态发射外部可观测?
我有一种感觉,我正在以一种错误的、非角度的、非RxJS的方式来处理这个问题。任何意见都将不胜感激。提前谢谢。
用第二个请求中的另一个值扩展数组值的常见问题。
extendedOrders$ = this.salesService.getOrders().pipe(
switchMap(orders => {
return forkJoin(orders.map(order => {
return this.salesService.getOrderCustomers(order.id).pipe(
map(customer => ({ ...order, customerName: customer.name })),
);
}));
}),
);
这里有一个解决方案,它不会对您已经做的事情有太大改变(因此可能更容易理解(:
this.salesService.getOrders().pipe(
mergeMap(orders =>
merge(
orders.map((order, index) => this.salesService.getOrderCustomers(order.id).pipe(
map(customers => customers.map(c => c.name).join(", ")),
map(customers => ({customers, index}))
))
).pipe(
scan((acc, {customers, index}) => {
const ordersSoFar = [...acc];
ordersSoFar[index]['customerName'] = customers;
return ordersSoFar;
}, orders)
)
)
).subscribe(orders => {
this.orders = orders;
});
这里最大的区别是,它不是在后台更新订单,让Angular变化检测发现订单已经改变,而是在每次更新时发出更新的订单。
一开始应该是一样的,但如果你愿意的话,可以直接在模板中使用可观察的内容(不需要自己订阅(。
您有可观察的订单orders$ = this.salesService.getOrders()
。用*ngFor="let order of orders$ | async"
在表中显示
然后你有功能提取一些额外的订单数据
getCustomers(order: Order): Observable<Customer> {
return /* data from service */
}
然后在组件模板中订阅每个订单的客户数据,并将其呈现为{{ getCustomers(order) | async }}
主要好处是订单数据已经可以呈现,同时可以提取其他数据。当然,这可以优化,客户数据可以缓存等等
并将changeDetection
设置为onPush
以获得更好的性能。