代码之家  ›  专栏  ›  技术社区  ›  spierala

RxJS乐观更新(强制发出乐观值)

  •  0
  • spierala  · 技术社区  · 5 年前

    如何在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 。但这感觉并不优雅:)

    1 回复  |  直到 5 年前
        1
  •  4
  •   Boyen    5 年前

    任何一个

    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。

    我更喜欢先开始的方法。

    stackblitz

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

    您可以添加另一个

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

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

        2
  •  1
  •   James Daniels    5 年前

    你可以通过以下方式实现这种行为 startWith operator .