Recently, I had a discussion on Stack Overflow regarding RxJS and the best approach for handling subscriptions in a reactive application. The debate was whether it's better to create a subscription for each specific side effect or minimize subscriptions in general. This topic is crucial for understanding how to structure a full reactive application and knowing when to switch between approaches. Clarifying this can help not only me but also others in avoiding unnecessary debates.
Setup Information
- All examples provided are in TypeScript
- To maintain focus on the question, no usage of lifecycles/constructors for subscriptions is included to keep it framework-agnostic
- Assume that subscriptions are added in constructor/lifecycle init
- Assume that unsubscribing is done in lifecycle destroy
Defining Side Effects (Angular Example)
- UI Update/Input (e.g.
value$ | async
) - Output/Upstream of a component (e.g.
@Output event = event$
) - Interaction between different services with varying hierarchies
Example Use Case:
- Two functions:
foo: () => void; bar: (arg: any) => void
- Two source observables:
http$: Observable<any>; click$: Observable<void>
foo
is called afterhttp$
emits without needing a valuebar
is called afterclick$
emits, requiring the current value ofhttp$
Case Study: Creating a Subscription for Each Specific Side Effect
const foo$ = http$.pipe(
mapTo(void 0)
);
const bar$ = http$.pipe(
switchMap(httpValue => click$.pipe(
mapTo(httpValue)
)
);
foo$.subscribe(foo);
bar$.subscribe(bar);
Case Study: Minimizing Subscriptions in General
http$.pipe(
tap(() => foo()),
switchMap(httpValue => click$.pipe(
mapTo(httpValue )
)
).subscribe(bar);
Personal Opinion Summarized
I believe that while subscriptions may initially complicate the Rx landscape by adding considerations like sharing your observable or not, separating your code based on what occurs when makes it easier to maintain, test, debug, and update in the future. Personally, I prefer creating a single observable source and individual subscriptions for each side effect in my code. If multiple side effects stem from the same observable source, I opt to share the observable and subscribe individually for each effect due to potentially differing lifecycles.