【问题标题】:RxJS optimistic update (force emit optimistic value)RxJS 乐观更新(强制发出乐观值)
【发布时间】:2020-02-28 08:28:27
【问题描述】:

您将如何在 RxJS 中实现乐观更新?看这个例子:

const todoIdSource: Subject<string> = new Subject();
const $todo = todoIdSource.pipe(
    tap(id => {
        const optimisticTodo: any = {
            userId: 1,
            id: id, // Use some value from the source observable
            title: "delectus aut autem",
            completed: false
        };
        // TODO force emit optimisticTodo! How? :)
    }),
    concatMap((id) => ajax('https://jsonplaceholder.typicode.com/todos/' + id)),
    map(response => response.response)
);

$todo.subscribe(value => console.log('TODO', value));

todoIdSource.next('1');

$todo 在 ajax 调用完成之前不会发出。 但我希望它在 todoIdSource 发出后立即发出乐观值。 最后 $todo 应该发出 2 个值:

  • 乐观值
  • ajax 结果的值

注意:

  • 乐观值不应触发 ajax 调用。
  • 乐观值应该能够使用来自可观察源 todoIdSource 的数据。

在 RxJS 中是否有一种优雅的方式来实现这一点?我可以想象引入第二个 Observable optimisticTodo$,然后将其与 $todo 合并。但这并不优雅:)

【问题讨论】:

    标签: javascript rxjs


    【解决方案1】:

    任何一个

    concatMap(id =>
        from(ajax("https://jsonplaceholder.typicode.com/todos/" + id)).pipe(
          map(response => response.response),
          startWith({...})
        )
      )
    

    请记住, startWith 必须是最后一个运算符(或至少在 map 之后)。 这可以确保您传递的值不会被映射,在这种情况下它不应该被映射,因为您使用映射来提取响应。

      concatMap(id =>
        merge(
          of({...}),
          from(ajax("https://jsonplaceholder.typicode.com/todos/" + id)).pipe(
            map(response => response.response)
          )
        )
      )
    

    两者都实现相同的目标:

    每当 todoIdSource 发出时,立即发出乐观的 todo,并在 ajax 调用结束时发出实际的 todo。

    我更喜欢 startWith 方法。

    stackblitz

    小附录:我假设订阅者实际上只对当前状态感兴趣。

    你可以添加另一个

      scan((acc,todo) =>({...acc,...{[todo.id]:todo}}), {}),
      map(v => Object.keys(v).map(k => v[k])),
    

    要实现这一点,请参阅addendum stackblitz

    【讨论】:

    • 指出startWith 应该是管道中的最后一项可能有用吗?
    • 在答案@spierala 中进一步澄清了这一点
    【解决方案2】:

    您可以使用startWith operator 实现该行为。

    【讨论】:

    • 谢谢!我稍微编辑了我的问题......乐观值应该能够使用来自可观察源todoIdSource的数据。我认为startWith 是不可能的
    • 然后 switchMap/concatMap 使用 startWith 到一个新的 observable
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-02
    • 1970-01-01
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多