# Programación Reactiva con RxJS
La programación reactiva se centra en flujos de información como secuencias ordenadas de datos.
Estos datos pueden proceder de eventos en la interfaz de usuario, un array, una petición http, etc.
Los 3 pilares de la programación reactiva son:
- Observable: Es aquel que notifica a aquellos suscritos los cambios que han habido.
- Suscripción: Es la acción de inscribirse a los eventos o notificaciones que emite el Observable.
- Observador: Es aquel que se encuentra suscrito a el observable, esperando a que lleguen cambios o notificaciones.
## ReactiveX (Extensiones Reactivas)
Es una combinación de las mejores ideas del patrón Observer, Iterador y la programación funcional. Tiene soporte e implementación para múltiples lenguajes, siendo RxJS la implementación para JavaScript.
[ReactiveX](https://reactivex.io/)
### Caracteristícas
- Basado en programación funcional
- Reduce código a través de métodos
- Manejo de errores para código asíncrono
- Desarrollo sencillo de código asíncrono
### Contrato Observable
Es lo que define como se comunican el Observable y el Observador. Por un lado el Observable puede comunicarse a través de:
- **NEXT**: Emite un valor al Observador.
- **ERROR**: Informa de un error al Observador y deja de emitir eventos.
- **COMPLETE**: Informa al Observador de que se ha completado la emisión de eventos, por lo que dejará de emitirlos.
Y el observador a través de:
- **SUBSCRIBE**: Es la petición de obtener valores del observable.
- **UNSUBSCRIBE**: Es la petición de dejar de obtener valores del observable.
## Diagrama de Canicas
Los diagramas de canicas están hechos para visualizar valores emitidos por un Observable en RxJS.
Son de gran ayuda cuando queremos enteneder cómo funcionan los métodos en RxJS.

Se representan a través de una línea de tiempo, en la que se irán pintando los diferentes eventos que ocurren en el observable.
En estos diagramas también podemos representar los eventos de COMPLETE y ERROR que podían emitir los observables.
*COMPLETE*

*ERROR*

También podemos representar una operación entre observables:

En [RxMarbles](https://rxmarbles.com/#merge) podemos ver, en forma de diagrama de canicas, todas las operaciones que tiene RxJS.
## RxJS
### Instalación
En mi caso decidí hacer un proyecto de prueba con vite, ya que me otorgaba un servidor muy rápido y con la posibilidad de tener TypeScript de manera muy cómoda.
```bash=
$npm create vite@latest
```
En este caso seleccione vanilla y TypeScript.
Una vez con el proyecto funcionando, instalo las dependencias e instalo rxjs:
```bash=
$npm i rxjs
```
Con esto listo ya tenemos un proyecto en marcha.
### Creación de Observables
Para crear un observable necesitamos importar la clase Observable de RxJS. Es importante saber, que por convención, los nombres de los observables terminan siempre con el símbolo '$'.
La clase Observable recibre como parámetro una función anónima con el subscriber. En ella es donde haremos uso de los métodos next, complete y error.
```typescript=
import { Observable } from "rxjs"
const observableAlfa$: Observable<number | string> = new Observable(subscriber => {
subscriber.next("Estoy observando")
subscriber.next(1)
subscriber.next(2)
subscriber.next("Adios")
})
/*...*/
```
De está forma hemos creado un Observable, que emite números y cadenas de texto. El soporte que tiene la librería para TypeScript es bastante bueno, por lo que podemos apoyarnos en el a la hora de tipar nuestros Observables.
Una vez tengamos el Observer definido, para comensar a emitir eventos solo debemos llamar al método susbscribe y pasarle el Observer como parámetro.
```typescript=
/*...*/
observableAlfa$.subscribe(observer)
/*...*/
```
### Creación de un Observer
Para crear un observer sólo debemos escribir un objeto que cumpla con la interfaz Observer, es decir, que implemente los métodos next, complete y error.
```typescript=
/*...*/
const observer: Observer<number | string> = {
next: (value: number | string ) => console.log(value),
complete: () => {},
error: (error: any) => console.log(error)
}
/*...*/
```
Con esto ya tendríamos un primer Observer que pueda suscribirse a nuestro Observable.
### Subject
Uno de los problemas del Observable común, es que puede llegar a responder de maneras diferentes a los Observers suscritos.
Supongamos que tenemos un Observable que genera números aleatorios, y dos Observers que se suscriben:
```typescript=
const numberRandom$: Observable<number> = new Observable(subscriber => {
subscriber.next(Math.round(Math.random() * 100))
})
const observer1: Observer<number> = {
next: (value: number | string ) => console.log(value),
complete: () => {},
error: (error: any) => console.log(error)
}
const observer2: Observer<number> = {
next: (value: number | string ) => console.log(value),
complete: () => {},
error: (error: any) => console.log(error)
}
numberRandom$.subscribe(observer1)
numberRandom$.subscribe(observer2)
```
Si vemos la consola podemos ver que la respuesta del Observable será diferente:

Esto es porque el Observable común es unicast, manda una respuesta a cada Observer, y no la misma.
Subject es un tipo especial de Observable, que nos permite envíar el mismo evento o valor a todos los Observers, es decir, es multicast.
Este tipo de Observable no recibe parámetros, y una instacia de dicho objeto puede ejecutar el método next.
```typescript=
/*...*/
const numberRandomBySubject$: Subject<number> = new Subject<number>()
numberRandomBySubject$.subscribe(observer1)
numberRandomBySubject$.subscribe(observer2)
numberRandomBySubject$.next(Math.round(Math.random() * 100))
/*...*/
```
Si vemos la consola, se verá el mismo resultado en ambos Observers:

Además un Subject se puede suscribir a otros Observables, de tal forma que el Subject puede hacer de intermediario y dar la misma respuesta a los Observers.
```typescript=
/*...*/
numberRandomBySubject$.subscribe(observer1)
numberRandomBySubject$.subscribe(observer2)
numberRandom$.subscribe(numberRandomBySubject$)
/*...*/
```
## Operadores
Los operadores son funciones puras. Tenemos dos tipos de operadores:
- Operadores creacionales
- Operadores pipeables
Los operadores pipeables crean un nuevo observable de salida sin modificar el observable de entrada.
### Operadores Creacionales
#### fromEvent
Está función es un generador de Observables en base a eventos en el DOM.
```typescript=
fromEvent(element, event)
```
- element: Elemento o nodo HTML, puede ser todo el document.
- event: String que representa el evento que queremos escuchar
*Ejemplo*
```typescript=
/**
* Observable que nos mostrará las letras que vayamos
* pulsando en el teclado
*/
const onKey$ = fromEvent(document, "keydown")
const keyObserver: Observer<Event> = {
next: (event) => console.log(event.key),
complete: () => console.log("Completado"),
error: (error: Error) => console.error(error)
}
onKey$.subscribe(keyObserver)
```
#### from y of
Los Observables from y of nos permiten generar observables a través de una serie de datos ya definidos.
- [of](https://rxjs.dev/api/index/function/of) genera un Observable a través de sus parámetros.

Podemos gestionar los valores del Observable en el queue del Event Loop si usamos asyncScheduler. Antes de la versión 8 se hacía con el operador from, sin embargo ahora se hace con [scheduled](https://rxjs.dev/deprecations/scheduler-argument#refactoring-of-of-and-from).
- [from](https://rxjs.dev/api/index/function/from) genera un Observable a través de un arreglo.

#### interval y timer
- [interval](https://rxjs.dev/api/index/function/interval) es un operador que genera un observable que emite valores numéricos por un intervalo de tiempo en milisegundos.

- [timer](https://rxjs.dev/api/index/function/timer) es un operador que genera un valor de un observable con un retraso de tiempo especificado en milisegundos.
### Operadores Pipeables
- **pipe**: todos los operadores creacionales tienen este método, genera una cadena de operadores que se pueden enlazar uno tras otro.
- **map**: itera sobre los valores que obtenemos del observable transformándolos.
- **filter**: filtra los valores de un observable dada una condición.
- **reduce**: combina todos los valores emitidos por un observable a través de una función acumuladora.
### Operadores de distinción
- **distinct**: Filtra los valores únicos de un Observable.
- **distinctUntilChanged**: Filtra los valores únicos de un Observable, si se repiten en secuencia.
- **distinctUntilKeyChanged**: Filtra los valores únicos (Objetos) de un Observable, si se repiten en secuencia en base a la propiedad que le pasemos como parámetro.
### Operadores de tiempo
Los operadores de tiempo nos ayudan a gestionar cómo y con qué frecuencia entregamos valores.
- **debounceTime**: Emite un valor de la fuente sólo después de que haya pasado un período de tiempo N milisegundos sin otra emisión de la fuente
- **throttleTime**: Deja pasar un valor y luego ignora los valores de la fuente durante los próximos N milisegundos.
- **auditTime**: Cuándo ve un valor de la fuente, lo ignora más los siguientes durante N milisegundos, y luevo emite el valor más reciente.
- **sampleTime**: Muestra la fuente del Observable en intervalos de N segundos.
¿Por qué son importantes los operadores de tiempo?
Imagina que necesitamos consultar a una API por unos valores que tenemos. Si son muchos valores corremos el riesgo de utilizar muchos recursos o generar muchas peticiones y llegar a un límite establecido.
✅ Pero a través de un operador como sampleTime, sólo hacemos una petición a una API cada 1 minuto, o cada 10 minutos por los valores emitidos, disminuimos la frecuencia de peticiones y el riesgo de llegar a un límite.
###### tags: `Programación Reactiva` `JavaScript` `RxJS`