使用 RxJS 的某种待办事项列表

Some sort of to-do list with RxJS

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

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

我使用 3 个可观察对象和 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 文档中搜索了运算符,但没有找到满足我需要的任何运算符或运算符组合。

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

无论哪种方式,您都可以通过创建一个在订阅时发出最新 elements 数组的可观察对象来摆脱全局状态 elements。在这个示例实现中,我将其命名为 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,可能需要一些额外的工作来确保您的类型在此处对齐。同样,您的示例中没有足够的信息来执行此操作,但我会把这个练习留给您。