首页 > 解决方案 > RxJS 的某种待办事项列表

问题描述

我目前在一个角度项目中使用 RxJS。在这个项目中,我有一个应该作为待办事项列表的列表:

  1. 一开始,列表中包含 5 个项目。
  2. 用户可以删除一个元素。
  3. 当一个元素被移除时,一个新元素被获取。
  4. 当列表为空时,将获取新元素。

我设法使用 3 个 observables 和 1 个状态来做到这一点:

// api.fetchElement -> ({ count: number, exclude: string[] }) => Observable<Element[]>
// removedElements$ -> Subject<string>

let elements = []

const initialElements$ = api.fetchElement({ count: 5 })

// removedElementId$ is a subject of string
// in which element ids are produced.
const reloadedElements$ = removedElementId$.pipe(
    // My API is eventualy consistent, so I need to exclude the removed items
    // for a short period.
    mergeMap(id => api.fetchElement({ count: 5, exclude: [ id ] })
)

const reloadedElementsWhenEmptyList$ = interval(3000).pipe(
    filter(() => elements.length < 5),
    mergeMap(() => api.fetchElement({ count: 5 - elements.length, exclude: elements.map(e => e.id) })
)

initialElements$.subscribe({
    next: newElements => elements = newElements
})

reloadedElements$.subscribe({
    next: newElements => elements = newElements
})

reloadedElementsWhenEmptyList$.subscribe({
    next: newElements => elements = newElements
})

当前的实现有效,但我想知道是否有一种方法可以执行相同的行为,但不必elements在可观察运算符中使用最终状态?

我在 RxJS 文档中搜索了运算符,但我没有找到任何满足我需要的运算符或运算符组合。

标签: angularrxjsreactivex

解决方案


您的设置有点奇怪,我不禁想知道是否有更好的方法来构建它。可悲的是,这里没有足够的知识。

无论哪种方式,您都可以elements通过创建一个在订阅时发出最新elements数组的 observable 来摆脱全局状态。在这个示例实现中,我称它为elements$

const initialElements$ = api.fetchElement({ count: 5 });

// removedElementId$ is a subject of string
// in which element ids are produced.
const reloadedElements$ = removedElementId$.pipe(
    // My API is eventualy consistent, so I need to exclude the removed items
    // for a short period.
    mergeMap(id => api.fetchElement({ 
      count: 5, 
      exclude: [ id ] 
    }))
);

const reloadedElementsWhenEmptyList$ = interval(3000).pipe(
    switchMap(_ => elements$),
    filter(elements => elements.length < 5),
    mergeMap(elements => api.fetchElement({ 
      count: 5 - elements.length, 
      exclude: elements.map(e => e.id) 
    }))
);

const elements$ = merge(
  initialElements$,
  reloadedElements$,
  reloadedElementsWhenEmptyList$
).pipe(
  startWith([]),
  shareReplay(1)
);

您会注意到,当我需要访问您的旧元素数组时,我只是订阅了elements$.

如果您使用的是 TypeScript,可能需要做一些额外的工作来确保您的类型在此处对齐。同样,您的示例中没有足够的信息来执行此操作,但我会将这个练习留给您。


推荐阅读