在 RxJS 中修补获取的对象的最佳方法是什么?

What is the best way to patch fetched objects in RxJS?

我有一个代码可以通过 id 获取图书

const fetchBook = (bookId: number) => {
    const title = 'Book' + bookId;
    // mimic http request
    return timer(200).pipe(mapTo({ bookId, title }));
}

const bookId$ = new Subject<number>();

const book$ = bookId$.pipe(
    switchMap(bookId => fetchBook(bookId)),
    shareReplay(1)
);

book$.subscribe(book => console.log('book title: ', book.title))

bookId$.next(1);

我有一个 API 方法来修补值和 returns 更新的对象:

const patchBook = (bookId: number, newTitle: string) => {
    return timer(200).pipe(mapTo({ bookId, title: newTitle }));
}

在我调用 patchBook(1, 'New Book Title') 后,我应该怎么做才能让 book$ 发出新值?

我可以将 book$ 显式声明为 Subject 并手动更新它。但这将是势在必行的,而不是被动的方法。

更新: 补丁被调用作为用户操作的结果在任何时候(或从不)

Upd2: 实际上 book$ 也可以在服务器端更改,我的真实代码如下所示:

const book$ = combineLatest([bookId$, currentBookChangedServerSignal$]).pipe...

与将 bookId 转换为 Book 所做的操作相同,您可以使用将 Book 转换为 patchBook。

const book$ = bookId$.pipe(
    switchMap(bookId => fetchBook(bookId)),
    mergeMap(({bookId, title}) => patchBook(bookId, title)),
    shareReplay(1)
);

更新:

patch并不总是被称为

有很多方法可以做到这一点,“最佳”方法实际上取决于您构建系统的方式。

假设您动态创建了一个用户单击的按钮,这会触发更新事件。

const patchBtn = document.createElement("button");
const patchBook$ = fromEvent(patchBtn, 'click').pipe(
  switchMap(_ => patchBook(bookId, title))
);

const basicBook$ = bookId$.pipe(
    switchMap(bookId => fetchBook(bookId))
);

const book$ = merge(patchBook$, basicBook$).pipe(
  shareReplay(1)
);

您可能希望 fromEvent 事件发出一些数据,而不是通过单击将 (bookId, title) 硬编码到流中,但您明白了。这只是完成工作的众多方法之一。

当然,删除 bookId$ 几乎总是可能的(并且是可取的),并用更具反应性的机制替换它,该机制以声明方式挂钩到 whatever/wherever ID 的来源首先。

您可以声明一个 fetchBook$ 可观察对象和一个 patchBook$ 主题。然后你的 book$ observable 可以是两者的合并。

const patchBook = (bookId: number, newTitle: string) => {
  return timer(200).pipe(
    mapTo({ bookId, title: newTitle }),
    tap(newBook=>this.patchBook$.next(newBook))
  );
}

const bookId$ = new Subject<number>();

const fetchBook$ = bookId$.pipe(
  switchMap(bookId => fetchBook(bookId)),
  shareReplay(1)
);

const patchBook$ = Subject<{ bookId: number, newTitle: string}>();

const book$ = merge(fetchBook$, patchBook$);


book$.subscribe(book => console.log('book title: ', book.title))

bookId$.next(1);
patchBook(2, 'Moby Dick');