Во-первых, здорово, что вы хотите очистить плохой наблюдаемый код. Если бы я просто критиковал ваш метод, я бы сделал что-то вроде этого:
import { observable } from 'fp-ts-rxjs/lib/Observable'; import { sequenceS } from 'fp-ts/lib/Apply'; import { tap } from 'rxjs/operators'; // Setup Raw Observables const welcomeMessage$ = this.http.get('some/api/welcomeMessage'); const apiCallTwo$ = this.http.get('some/api/chart'); const language$ = languageObs(); const dataRange$ = dateRangeObs(); const users$ = usersObs(); // Encapsulate Side Effects const dateRangeSideEffect$ = dateRange$.pipe( tap(([startDate, endDate]) => { this.startDate = startDate; this.endDate = endDate; }) ); const usersSideEffect$ = users$.pipe( tap(users => this.setUsers(users)) ); const apiCallTwoSideEffect$ = apiCallTwo$.pipe( tap(chart => this.chartData = chart) ); // Construct Merged Observable const mergedObs$ = sequenceS(observable)({ welcomeMessage: welcomeMessage$, apiCallTwo: apiCallTwoSideEffect$, language: language$, dataRange: dateRangeSideEffect$ users: usersSideEffect$ }) // Setup Subscription const mySub = mergedObs$ .subscribe(({ welcomeMessage, language }) => { this.setWelcomeMessage(welcomeMsg, lang); // all data aquired, wire-up everything this.launch(); } );
Но даже это проблематично, поскольку возможно, что language, dataRange и пользователи могут генерировать более одного раза! В будущем мы, возможно, захотим реагировать на изменения в users, dateRange или языке, вместо того, чтобы повторно запускать весь этот блок кода. В этом случае мы должны просто вернуть необработанные наблюдаемые как сами значения и распаковывать только тогда, когда нам нужно.
В ответ вы, вероятно, передадите в компонент все наблюдаемые, которые хотите наблюдать, а затем воспользуетесь несколькими перехватчиками, чтобы развернуть значения. Вот пример ловушки rxjs для такого случая (простите за машинописный текст, если вы не знакомы):
import { some, none, fromNullable } from 'fp-ts/lib/Option'; import { Observable } from 'rxjs' import { useEffect, useState } from 'react' const useRxjs = <T>(obs: Observable<T>, init?: T) => { const [state, setState] = useState(fromNullable(init)); const [errorState, setErrorState] = useState(none); const [completeState, setCompleteState] = useState(false); useEffect(() => obs .subscribe( n => setState(some(n)), e => setErrorState(some(e)), () => setCompleteState(true), ).unsubscribe, [obs, init]); return [state, errorState, completeState]; }
В angular вы бы даже не подписались на свой класс компонента. Вы бы удалили побочные эффекты и сделали бы что-нибудь вроде:
import { observable } from 'fp-ts-rxjs/lib/Observable'; import { sequenceS } from 'fp-ts/lib/Apply'; import { tap } from 'rxjs/operators'; @Component({ template: ` <div *ngIf="myData$ | async as myData"> {{ myData.welcomeMessage }} {{ myData.chart }} {{ myData.language }} {{ myData.dataRange }} {{ myData.users }} </div> ` }) export class MyComponent { readonly welcomeMessage$ = this.http.get('some/api/welcomeMessage'); readonly chart$ = this.http.get('some/api/chart'); readonly language$ = languageObs(); readonly dataRange$ = dateRangeObs(); readonly users$ = usersObs(); readonly myData$ = sequenceS(observable)({ welcomeMessage: welcomeMessage$, chart: chart$, language: language$, dataRange: dateRange$ users: users$ }) }
И ваш компонент будет обновляться по мере изменения данных.
Надеюсь, это откроет вам глаза на некоторые другие закономерности. Извините, я не включил полный пример компонента React. Уже поздно, и я очень устал.