The RxJs Survival Kit — 20 operators to save your skin
One of the hype of the last years is Reactive Programming. It consists in to react to events and manipulating these events. At the browser, we have lots of native features that are reactive, such as addeventlistener. You define an event to trigger a specific function. We also use something like reactive programming when we use pub/sub or observer patterns.
The RxJs is an abstraction to Javascript to work with reactive programming. It is written by the ReactiveX company and also has the implementation of other languages like Java, Swift, C#, etc…
The Angular community makes huge use of RxJs features since Angular API is written in RxJs. One of the native reactive behaviors:
- Forms;
- HTTP Requests;
- Components Outputs;
- Router;
I defined the 20 operators more used in RxJS, it was really hard to choose, because of how many experiences you have used those functionalities more operators and strategies you will know.
It’s important to keep in mind that this is not a tutorial about RxJs, it is just a list of some important operators. I will give some pieces of information and some use cases.
[Update]
I created a Youtube Playlist in Portuguese explaining a little bit more about these next operators. Feel free to comment
Sources + Pipes + Subscription
First, we need to understand how it works, the basic flow. You can imagine this flow as a barrel, that at the beginning of the barrel we will receive an event and at the end, we will have the value from this event. The events are the Sources and the place we receive the values is the Subscription.
For example, we have a click event from the browser using the addEventListener and print this event.
Here we have in the same API the Source and the Subscription. If we can split it we could define the Source from document.addEventListener(‘click’` and the Subscription as the function to print the event value event => console.log(event)).
Working with RxJs we can write it:
Where the Source is fromEvent(document, ‘click’) and the Subscription is subscribe(event => console.log(event)). The Source will emit a value and the subscription will receive these values.
We can also make some manipulations on those events before receiving the values. The place we add the manipulations methods is the Pipe. There you can filter the value, map it — just like in arrays — and make other manipulations.
Observables
The sources are the event emitters in the Sources + Pipes + Subscription equation. They could be of many types, but they always emit events. You can think the events are data flows to be used by something.
Events sources could be a browser event, a timer, a return from a promise, a callback from a function, and others. But to be manipulated by the RxJs operators they need to be converted to an Observable.
The Observable is a collection how works in a unidirectional way and emits notifications values whenever a change occurs in one of its items.
Subscribing
Is strictly important to subscribe to the stream, without this, the stream will not emit any event. The subscriber will allow the source starts to emit their values.
A subscription receives 3 event states: Next, Error, and Complete.
Thinking of a promise it’s like then, catch, and finally.
When the values are emitted by the source they will be received at the next function, errors will be received at the error, and a different concept here is complete.
Creation
The Sources, usually, are Observables of an event, array, strings, promise, and we can create it using RxJs methods.
#1 — of
Will create an Observable, emit the values and complete the stream.
Use Case: Pass an observable to an observable interface, combine values with other observable.
#2 — interval
Emit numbers in sequence based on provided timeframe. It will wait for the timeframe to start to emit the values.
Use Case: We can use it to create pooling to HTTP requests to update a data table, for example.
#3 — fromEvent
Turn any event into an observable sequence.
Use Case: You can trigger some behaviors on the event click.
#4 — from
Turn an array, promise, or iterable into an observable.
Use Case: Working reactively with promise.
We have other creation operators including Ajax, timer, etc. Each of them has their behaviors.
Manipulating
Between the beginning and the end of the barrel, we can do many things. We can manipulate the streams in lots of ways. Here I will tell you about some of the more useful pipable operations to manipulate the streams.
#5 — tap
Transparently perform actions or side-effects, such as logging.
Use Case: Perform any non-returned logic or logging
#6 — filter
Emit values that pass the provided condition. It is like the if operator, but without else statement.
Use Case: Check if some satisfy the condition. We can also create different streams to manipulate different conditions after combing them.
#7 — take
Emit provided a number of values before completing.
Use Case: To complete stream on specific repetition.
#8 — pluck
Select properties to emit.
Use Case: Get a nested property of an emitted object.
#9 — startWith
Emit given value first.
Use Case: Make sure that some value will be emitted on subscribing to this stream, in the case of the source having a delay to emit the first value. For example an interval, that only emits the first value after the timeframe, you can add a startWith to emit the value on subscribing.
#10 — takeUntil
Emit values until provided observable emits
Use Case: To close a subscription on destroying a component
#11 — debounceTime
Discard emitted values that take less than the specified time between output. It basic will stop emitting values until stop to receive events in a specified time.
Use Case: We add a debounceTime in input to make a search, without this discarding values all typed values will be searched.
#12 — distinctUntilChanged
Only emit when the current value is different than the last.
Use Case: You can use this to prevent emitting duplicate values from events.
#13 — map
Apply projection with each value from the source.
Use Case: Make any transformation to the values.
These transformations could not return another stream, for those proposes we need to use the operators from the next section.
Transforming
Here are the operators that will transform the streams. You can transform each emitted value and request a value from another stream.
#14 — mergeMap
Map to observable, emit values concurrently. You use this when you want to emit values even when values change, and you don’t want to stop the previous values.
Use Case: We use a lot of ngrx effects when we need to dispatch actions after a request.
#15 — switchMap
Map to observable, complete previous inner observable, emit values.
Use Case: This is used when you don’t want to make your stream concurrently. It will complete the previous and start a new stream.
Combining
There are lots of ways to combine your streams and react from them. Combining is a strategy to join streams and make the logic easy.
#16 — merge
Turn multiple observables into a single observable.
Use Case1: Makes the first fetch to get data, and after makes others when to click to update.
Use Case2: Combine many triggers to make a request, when any of them emits a value it will trigger the switchMap and make the request.
#17 — combineLatest
When any observable emits a value, emit the latest value from each. It will just emit when all observables emit a value
Use Case1: You can create a ViewModel with all observables you need.
Use Case2: You can compare values combined and emit what you want.
Emitting
We are talking about reacting from events like clicks, requests, timing, but we can create an event source. With this event source, we can share values to other parts of the application or emit a value to others who reacts to it.
#18 — Subject
Emits the current value.
#19 — BehaviorSubject
A Subject that requires an initial value and emits its current value and saves it to new subscribers.
UseCases
Making other streams react:
Close other streams:
Handle error
#20 — catchError
This is one of the ways we have to manage the errors from streams. Using catchError, we always need to return an observable.
It’s important to know that if we do not handle errors the stream will be turned off and break the flow.
Use Case: We can just return an observable with the error value, but we can define a callback to retry the operation, call the initial state of a list, open an alert message.
What to study after that?
Here I exposed a selection of 20 operators from RxJs, those operators you could use to really save your skin. They are the most used operators and for general uses. There are more than 450 operators in ReactiveX project, some of them are variations from the basic I mentioned here. You can try them to fit in some more specific cases.
RxJs is just a great lib to allow us to code reactively, but the most important is learning to think reactively! Try to make some tests using reactive programming and apply these operators and concepts I list here.
For each operator, I add a link to learnrxjs.io, where you can find many operators docs and examples.
You can also check some example diagrams as I add here at rxmarbles.com.
I also create a repo to make some tests, feel free to contribute. There I wrote some considerations about some operators and made some tests with jest.
I hope I could help you to learn more about RxJs and Reactive Programming.