getOne и getAll с локальным наблюдаемым кэшем и удаленной базой данных
У меня есть список "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

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

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