【问题标题】:What is the best way to patch fetched objects in RxJS?在 RxJS 中修补获取的对象的最佳方法是什么?
【发布时间】:2021-10-14 03:08:25
【问题描述】:

我有一个通过 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 方法可以修补值并返回更新的对象:

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

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

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

更新:该补丁在任何时候(或从不)由于用户操作而被调用

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

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

【问题讨论】:

    标签: rxjs rxjs6 rxjs-observables


    【解决方案1】:

    与将 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$ 几乎总是可能的(并且是可取的),并将其替换为更具反应性的机制,该机制首先以声明方式挂钩到ID 的来源。

    【讨论】:

      【解决方案2】:

      你可以声明一个 fetchBook$ observable 和一个 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');
      

      【讨论】:

      • 我还不如只做书作为主题,但我在寻找更优雅的反应式解决方案
      • 经过进一步思考后刚刚更新了我的答案。希望这更符合目标。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-17
      • 1970-01-01
      • 1970-01-01
      • 2010-11-08
      相关资源
      最近更新 更多