在我的客户详细信息组件中,我有以下代码可以实现我之后的目标,但不是我认为可能的反应/可观察方式。
不是将this.isLoading = true;
包装在if语句中,是否有办法使用反应式编程技术?如果首先检索客户,可能通过取消/删除延迟的可观察量?或者,我是否采取了错误的方式?
export class CustomerDetailComponent implements OnInit {
customer: Customer;
errorMessage: string;
isLoading: boolean;
constructor(
private customerService: CustomerService,
private route: ActivatedRoute,
private router: Router,
private location: Location
) { }
ngOnInit() {
let idParam = this.route.params
.distinctUntilChanged(params => params['id']);
idParam.subscribe(params =>
{
this.errorMessage = '';
});
idParam.delay(300).subscribe(params =>
{
if (!(this.customer && this.customer.id == params['id']))
this.isLoading = true;
});
idParam.switchMap((params: Params) => this.customerService.getCustomer(params['id']))
.subscribe(customer =>
{
this.customer = customer;
this.isLoading = false;
},
error => this.errorMessage = error);
}
}
答案 0 :(得分:6)
你可以写下这些内容:
function getCustomer(id) {
return Observable.of({'name': 'John', id}).delay(500);
}
Observable.of({'id': 42})
.distinctUntilChanged(params => params['id'])
.do(() => {
// this.errorMessage = '';
})
.switchMap((params) => {
return Observable.combineLatest(
Observable.of(true).delay(300).startWith(null), // delay Observable
getCustomer(params['id']).startWith(null), // customer Observable
function(delay, customer) { // selector function
if (customer) {
return customer;
}
if (delay && !customer) {
console.log('this.isLoading = true;');
}
return null;
})
.filter(customer => customer)
.distinctUntilChanged(customer => customer['id']);
})
.subscribe(
customer => {
console.log('this.isLoading = false;');
console.log(customer);
// this.customer = customer;
},
error => {
// this.errorMessage = error;
}
);
查看现场演示:https://jsbin.com/nebutup/5/edit?js,console
内部combineLatest()
收到两个Observables:
然后还有投影功能用于选择我们想要进一步传播的内容。两个Observable都使用.startWith(null)
来确保它们至少有一个项目被释放,因此combineLatest()
将被其中任何一项的更改触发。然后我们可以很容易地知道发出的第一个Observable是延迟还是客户。
然后还有filter()
删除所有null
值和distinctUntilChanged()
以确保我们不会两次发出相同的客户(这处理客户首先完成的情况)。
然后,当我们运行此演示并且首先触发延迟时,输出如下:
this.isLoading = true;
this.isLoading = false;
{ name: 'John', id: 42 }
这意味着我们首先显示加载然后隐藏它。
然后,当我们将getCustomer()
更改为先完成时:
function getCustomer(id) {
return Observable.of({'name': 'John', id}).delay(100);
}
我们将获得以下内容:
this.isLoading = false;
{ name: 'John', id: 42 }
这意味着我们从不显示任何负载。
答案 1 :(得分:0)
这是带有可重用运算符的rxjs 6管道方法:
export function delayIndicator<T>(delay: number, start: () => void, complete: () => void): OperatorFunction<T, T> {
const loadingShown$ = timer(delay).pipe(
tap(() => start()),
mapTo(true),
startWith(false)
);
return (input$) =>
combineLatest([input$, loadingShown$]).pipe(
take(1),
map(([input, delayShown]) => {
if (delayShown) {
complete();
}
return input;
})
);
}
myObservable$.pipe(delayIndicator(300, () => this.loading = true, () => this.loading = false));