Angular 带有本地可观测缓存和远程数据库的getOne和getAll

Angular 带有本地可观测缓存和远程数据库的getOne和getAll,angular,rxjs,Angular,Rxjs,我有一个“待办事项”列表,它将在用户会话期间和会话之间发生变化,并以各种组件显示给用户。我想采用“单一真相来源”和“尽可能长时间地保留数据流”的最佳实践启发法,而不必一直使用ngrx或类似方法 具体地说,我想创建1)todos$observable和2)从$todos管道传输的单个todo$observable,以及3)一个getByTodoId函数,该函数在本地查找todo,然后在未找到todo时进行http调用。不过,我想对next->http->next循环非常小心 我现在所拥有的: to

我有一个“待办事项”列表,它将在用户会话期间和会话之间发生变化,并以各种组件显示给用户。我想采用“单一真相来源”和“尽可能长时间地保留数据流”的最佳实践启发法,而不必一直使用ngrx或类似方法

具体地说,我想创建1)todos$observable和2)从$todos管道传输的单个todo$observable,以及3)一个getByTodoId函数,该函数在本地查找todo,然后在未找到todo时进行http调用。不过,我想对next->http->next循环非常小心

我现在所拥有的:

todoService

let todos: Array<todo>;
let todos$: ReplaySubject<Array<todo>>;

getTodoById(id): Observable<todo> => {

    // looks in a todo array
    let todo = todos.find(todo => todo.id === id)

    if (todo) {
      return of(todo);
    }

    return http.post(urlgetTodoById, {id}).pipe(
      map((todo) => {

        todos.push(todo)
        todos$.next(todos)
        return todo;
      })
    );
  }
let todo$; // maybe this should be like ReplaySubject<todo>?

getTodoById = (id) => todos$.pipe(

  a) look id in todos$ and if not found
  b) make api call for specific todo then add to todos$
)
我想要的是:

todoService

let todos: Array<todo>;
let todos$: ReplaySubject<Array<todo>>;

getTodoById(id): Observable<todo> => {

    // looks in a todo array
    let todo = todos.find(todo => todo.id === id)

    if (todo) {
      return of(todo);
    }

    return http.post(urlgetTodoById, {id}).pipe(
      map((todo) => {

        todos.push(todo)
        todos$.next(todos)
        return todo;
      })
    );
  }
let todo$; // maybe this should be like ReplaySubject<todo>?

getTodoById = (id) => todos$.pipe(

  a) look id in todos$ and if not found
  b) make api call for specific todo then add to todos$
)

您可以使用
BehaviorSubject
进行缓存,它有一个
.getValue()
方法,可用于获取当前值

let todos$=new BehaviorSubject({})

getTodoById = (id) => todos$.pipe(

if(todos$.getValue()[id])
  return todos$.pipe(pluck(id))
else 
  return http.post(urlgetTodoById, {id}).pipe(tap(todo=>
     todo$.next({[id]:todo,...todo$.getValue()})
    )
  )
)

我希望能够在模板中迭代TODO,所以我将其作为数组保存。我使用ReplaySubjects来保存todo,以便getTodoById可以在http调用返回之前返回todo$,而不触发事件

todoCache: Array<{todoId: string, todo$: ReplaySubject<Todo>}>

getAllRemote(): void { 
    this.http
    .post(URL_GET_TODOS)
    .pipe(
      tap((todo) => {

        this.addTodo(todo)
      })
    );
}

getOneRemote(todoId: string): void {
   this.http
      .post(URL_GET_ONE_TODO, { todoId })
      .pipe(
        tap((todo: Todo) => {
          this.addTodo([todo]);
        })
      );
}

getTodoById(todoId: string): ReplaySubject<Todo> { 
    const cachedTodo = this.todo.find(
      cachedTodo => cachedTodo.todoId === todoId
    );

    if (cachedTodo) {
      return cachedTodo.todo$;
    } else {
      this.chatUses.push({ todoId, todo$: new ReplaySubject(1) });
      this.apiGetChatUseByChatId(chatId, privateChat);
    }
}

addTodo(toAdd: Array<Todo>): void {

      for (let i = 0; i < toAdd.length; i += 1) {
        const index = this.todoCache.findIndex(
          entry => entry.todoId === toAdd[i].id
        );

        if (index === -1) {
          this.chatUses.push({
            todoId: toAdd[i].id,
            todo$: new ReplaySubject(1)
          });
          this.todoCache[this.todoCache.length - 1].todo$.next(toAdd[i]);
        } else {
          this.todo[index].todo$.next(toAdd[i]);
        }
      }
}
todoche:Array
getAllRemote():void{
这是http
.post(URL\u GET\u TODOS)
.烟斗(
轻触((todo)=>{
this.addTodo(todo)
})
);
}
getOneRemote(todoId:string):无效{
这是http
.post(URL\u GET\u ONE\u TODO,{todoId})
.烟斗(
轻触((待办事项:待办事项)=>{
这个。addTodo([todo]);
})
);
}
getTodoById(todoId:string):ReplaySubject{
const cachedTodo=this.todo.find(
cachedTodo=>cachedTodo.todoId===todoId
);
if(cachedTodo){
返回cachedTodo.todo$;
}否则{
this.chatUses.push({todoId,todo$:new ReplaySubject(1)});
this.apiGetChatUseByChatId(chatId,privateChat);
}
}
addTodo(toAdd:Array):无效{
for(设i=0;ientry.todoId==toAdd[i].id
);
如果(索引==-1){
这个.chatus.push({
todoId:toAdd[i].id,
todo$:新的ReplaySubject(1)
});
this.todoCache[this.todoCache.length-1].todo$.next(toAdd[i]);
}否则{
this.todo[index].todo$.next(toAdd[i]);
}
}
}

你的问题是什么?你能分享一下你到目前为止的尝试吗?嘿,库尔特,我对这个问题做了一些编辑来澄清。谢谢todo当前是按每个todo对象的属性排序的数组。我想你是在建议把它作为地图存储起来搜索它更好?我最终做了一些不同的事情,但这肯定让我找到了解决方案,所以谢谢!我将对此进行投票\很高兴它有帮助,使用数组对象也是一种类似的逻辑。只需要使用filter()而不是pull()