getOne и getAll с локальным наблюдаемым кэшем и удаленной базой данных

getOne и getAll с локальным наблюдаемым кэшем и удаленной базой данных

21.03.2020 01:11:47 Просмотров 23 Источник

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

В частности, я хочу создать 1) todos$ observable и 2) отдельные todo$ observables, которые передаются по конвейеру из $todos и 3) функцию getByTodoId, которая ищет todo локально, а затем делает вызов http, если он не найден. Однако я хочу быть очень осторожным в следующем цикле -> 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;
      })
    );
  }

тодокомпонент

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

тодокомпонент

localTodo$ = todoService.getByTodoId(id) 
У вопроса есть решение - Посмотреть?

Ответы - getOne и getAll с локальным наблюдаемым кэшем и удаленной базой данных / getOne and getAll with local Observables cache and remote database

Fan Cheung

21.03.2020 05:20:22

Вы можете использовать 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()})
    )
  )
)
wcjord

22.03.2020 08:15:48

Я хотел иметь возможность повторять todos в шаблонах, поэтому я сохранил его в виде массива. Я использовал ReplaySubjects для удержания todos, чтобы getTodoById мог сделать return 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]);
        }
      }
}
Закрыть X