getOne и getAll с локальным кэшем Observables и удаленной базой данных - PullRequest
0 голосов
/ 21 марта 2020

У меня есть список «задач», которые будут меняться во время и между сеансами пользователя и отображаются для пользователя в различных компонентах. Я хочу использовать «единый источник правды» и «хранить данные в потоке как можно дольше», наилучшую эвристику, не прибегая к использованию ngrx или подобного.

В частности, я хочу создайте 1) todos $ observable и 2) отдельные todo $ observables, которые передаются из $ todos, и 3) функцию getByTodoId, которая ищет todo локально, затем выполняет http-вызов, если он не найден. Я хочу быть очень осторожным в следующем -> http -> next l oop хотя.

Что у меня сейчас:

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;
      })
    );
  }

todoComponent

localTodo = await getByTodoId.toPromise()

Что я хочу:

todoService

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$
)

todoComponent

localTodo$ = todoService.getByTodoId(id) 

Ответы [ 2 ]

1 голос
/ 21 марта 2020

Вы можете использовать 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()})
    )
  )
)
0 голосов
/ 22 марта 2020

Я хотел иметь возможность перебирать задачи в шаблонах, поэтому я сохранил их как массив. Я использовал ReplaySubjects для хранения задач, чтобы getTodoById мог возвращать todo $, не вызывая событие, пока не вернется вызов http.

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]);
        }
      }
}
...