我创建了一个糟糕的勒芒更新轮询机制。它检查URL上的更新,然后调度消息以更新对象。这项工作,但现在我只想在对象发生变化时调度此更新,因为该对象可能已经是最新的。为了能够验证这些对象,我创建了一个哈希:如果哈希值相等,那么对象也是如此。
现在,这种效果很好:
@Effect()
pollBatStore = this.actions$
.ofType(BatStoresActions.POLL_BAT_STORE)
.map((action: BatStoresActions.PollBatStore) => action.payload)
.mergeMap((upd: BatUpdateJSON) => this.batStoreStorage.getBatStoreFromUrl(upd['_links'].pollUrl.href))
.map((batStore: BatStore) => {
return new UpdateBatStore(batStore);
});
但显然,当更新通知进入时,这将始终在商店中更新我的对象。所以我想将我从API获取的对象与我在ngrx商店中的对象进行比较。现在,我如何组合对象以便比较它们的属性?
我试过这个,但它不起作用:
@Effect()
pollBatStore = this.actions$
.ofType(BatStoresActions.POLL_BAT_STORE)
.map((action: BatStoresActions.PollBatStore) => action.payload)
.mergeMap((upd: BatUpdateJSON) => this.batStoreStorage.getBatStoreFromUrl(upd['_links'].pollUrl.href))
.withLatestFrom((bs: BatStore) => this.batStoreRepository.getBatStoreByApiKey(bs.apiKey))
.map(([batStore: BatStore, batStoreInMemory: BatStore]) => {
if (batStore.apiHash !== batStoreInMemory.apiHash) {
return new UpdateBatStore(batStore);
} else {
return {type: 'NO_ACTION'}
}
});
我认为我以错误的方式使用.withLatestFrom,但我需要来自我的对象的apiKey属性才能选择它。所以我想我需要另一个选择器,但哪一个呢?我无法弄清楚。
更新:这似乎现在正在运作,但我认为这是一个糟糕的解决方案。特别是通过和检查“假”'返回值两次。但它做了我想要的:当ngrx商店中的哈希与我的REST api告诉我相同时,它不会更新。
@Effect()
pollBatStore = this.actions$
.ofType(BatStoresActions.POLL_BAT_STORE)
.map((action: BatStoresActions.PollBatStore) => action.payload)
.switchMap((upd: BatUpdateJSON) => {
return this.batStoreRepository.getBatStoreByApiKey(upd.apiKey)
.take(1)
.map((bs: BatStore) => {
console.log('Found batstore in mem: ', bs);
if (upd.apiHash !== bs.apiHash) {
return bs;
} else {
return false;
}
});
})
.switchMap(result => {
console.log('Result from hash check ', result);
if (result instanceof BatStore) {
return this.batStoreStorage.getBatStoreFromUrl(result.links['self'].href)
.take(1)
.map(newBs => {
console.log('New object: ', newBs);
return newBs;
});
} else {
return Observable.of(false);
}
})
.map(result => {
console.log('Final result', result);
if (result instanceof BatStore) {
return new UpdateBatStore(result);
} else {
return new NoAction();
}
});
答案 0 :(得分:0)
几个月后,我发现forkJoin可能是更好的解决方案。起初我没有得到这个,因为从ngrx商店中选择一个对象会返回一个未完成的Observable(source)。所以forkJoin也从未完成。添加.take(1)解决了这个问题。
所以我改写了我的效果,现在它看起来像这样:
@Effect()
pollBatStore = this.actions$
.ofType(BatStoresActions.POLL_BAT_STORE)
.pipe(
map((action: BatStoresActions.PollBatStore) => action.payload),
mergeMap((upd: BatUpdateJSON) => forkJoin(
of(upd),
this.batStoreRepository.getBatStoreByApiKey(upd.apiKey)
)),
filter(([upd, batStore]) => {
return upd.apiHash !== batStore.apiHash;
}),
mergeMap(([upd, batStore]) => {
return this.batStoreStorage.getBatStoreFromUrl(upd._links.pollUrl.href);
}),
map(newBatStore => new UpdateBatStore(newBatStore))
);
我不确定这是否是正确答案,但我认为无论如何分享可能会有所帮助。我仍然想知道的一件事是我认为效果应该总是返回一个动作。此代码可以正常运行,但如果链在过滤器处停止会发生什么?