您将如何在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个值:
注意:
todoIdSource
来源的数据。在RxJS中是否有一种优雅的方法来实现这一目标?我可以想象引入第二个Observable optimisticTodo$
,然后将其与$todo
合并。但这并不优雅:)
答案 0 :(得分:3)
要么
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方法。
小附录:我假设订阅者实际上只对当前状态感兴趣。
您可以添加另一个
scan((acc,todo) =>({...acc,...{[todo.id]:todo}}), {}),
map(v => Object.keys(v).map(k => v[k])),
要实现该目标,请参见addendum stackblitz
答案 1 :(得分:1)
您可以使用startWith
operator实现该行为。