Last week I answered an RxJS question where I got into a discussion with another community member about: "Should I create a subscription for every specific side effect or should I try to minimize subscriptions in general?" I want to know what methology to use in terms of a full reactive application approach or when to switch from one to another. This will help me and maybe others to avoid unecesarry discussions.
Setup info
- All examples are in TypeScript
- For better focus on question no usage of lifecycles/constructors for subscriptions and to keep in framework unrelated
- Imagine: Subscriptions are added in constructor/lifecycle init
- Imagine: Unsubscribe is done in lifecycle destroy
What is a side effect (Angular sample)
- Update/Input in the UI (e.g.
value$ | async
) - Output/Upstream of a component (e.g.
@Output event = event$
) - Interacton between different services on different hierarchies
Exemplary usecase:
- Two functions:
foo: () => void; bar: (arg: any) => void
- Two source observables:
http$: Observable<any>; click$: Observable<void>
foo
is called afterhttp$
has emitted and needs no valuebar
is called afterclick$
emits, but needs the current value ofhttp$
Case: Create a subscription for every 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: Minimize subscriptions in general
http$.pipe(
tap(() => foo()),
switchMap(httpValue => click$.pipe(
mapTo(httpValue )
)
).subscribe(bar);
My own opinion in short
I can understand the fact that subscriptions make Rx landscapes more complex at first, because you have to think about how subscribers should affect the pipe or not for instance (share your observable or not). But the more you separate your code (the more you focus: what happens when) the easier it is to maintain (test, debug, update) your code in the future. With that in mind I always create a single observable source and a single subscription for any side effect in my code. If two or more side effects I have are triggered by the exact same source observable, then I share my observable and subscribe for each side effect individually, because it can have different lifecycles.