Operadores básicos en RXJS
Tags: rxjs, spanish, javascript, webdev
Published: 2023-04-21 22:15:57

Un operador es una función que se usa en un observable y controla y emite solo la información que nos interesa de la forma en que la necesitamos.  

## map
Nos permite transformar o extraer lo que emite el observable en algo diferente, manteniendo la estructura del flujo original. `map` es uno de los operadores más comunes y poderosos en RxJS, y se utiliza ampliamente para realizar transformaciones en los datos emitidos por un observable.

La sintaxis básica de map es la siguiente:

```js
observable$.pipe(
  map(valor => nuevoValor)
)
```
Donde observable$ es el flujo de datos observable del cual se desean transformar los valores, y valor => nuevoValor es una función de transformación que toma cada valor emitido por el observable y devuelve un nuevo valor transformado.

Miremos su grafica de canicas:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tl24z550330jw2yqfhd1.png)


ejemplo: 
Transformación de valores: La función de transformación que se pasa como argumento a map es aplicada a cada valor emitido por el observable. Esta función toma el valor original y devuelve un nuevo valor transformado. Por ejemplo:

```js
const numeros$ = of(1, 2, 3, 4, 5); // Observable que emite los números del 1 al 5

numeros$.pipe(
  map(numero => numero * 2) // Transforma cada número emitido por el observable multiplicándolo por 2
).subscribe(resultado => console.log(resultado));

```
El resultado de este código sería imprimir en la consola: 2, 4, 6, 8, 10, que son los valores originales multiplicados por 2.

## filter
El operador `filter` es una función de filtrado que se utiliza para emitir solo aquellos elementos de un flujo de datos observable que cumplan con una condición especificada. En otras palabras, filter permite seleccionar elementos de un observable que satisfagan una condición dada y descartar aquellos que no la cumplan.

La sintaxis básica de filter es la siguiente:

```js
observable$.pipe(
  filter(condicion)
)
```
Donde observable$ es el flujo de datos observable del cual se desean filtrar los elementos, y condicion es una función de predicado que especifica la condición que debe cumplir cada elemento emitido para ser seleccionado.
`filter` permite utilizar cualquier función de predicado que devuelva un valor booleano para evaluar la condición de filtrado. Esto proporciona una gran flexibilidad para especificar condiciones complejas basadas en cualquier propiedad o característica de los elementos emitidos por el observable.

Esta es su grafica de canicas:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8wv86ubm5a2psrracpv.png)


veamos un ejemplo: 

```js
const personajes = [
    {
      tipo: 'heroe',
      nombre: 'Batman',
    },
    {
      tipo: 'heroe',
      nombre: 'Robin',
    },
    {
      tipo: 'villano',
      nombre: 'Joker',
    },
  ];

  from(personajes)
    .pipe(filter((personaje) => personaje.tipo === 'heroe'))
    .subscribe(console.log);
```
El resultado de este código sería imprimir en la consola `{tipo: "heroe", nombre: "Batman"}, {tipo: "heroe", nombre: "Robin"}`, que son los personajes que cumplen con la condición especificada en la función de predicado.

Una característica importante de filter es que los elementos que no cumplen con la condición especificada en la función de predicado no se emiten en el resultado del observable. Esto significa que solo los elementos que satisfacen la condición son emitidos, y los demás son ignorados y no se propagan en el flujo de datos.

## tap
El operador tap es un operador de utilidad que permite realizar acciones secundarias o efectos secundarios en los elementos que fluyen a través de un flujo de datos observable, sin afectar la emisión o transformación de los elementos en sí. Es una herramienta poderosa para depurar, registrar o ejecutar lógica adicional en un flujo de datos observable sin modificar su comportamiento.

La sintaxis básica de tap es la siguiente:

```js
observable$.pipe(
  tap(funcionEfecto)
)
```
Donde observable$ es el flujo de datos observable al cual se desea aplicar el efecto secundario, y funcionEfecto es una función que se ejecuta para cada elemento emitido por el observable, sin modificar el elemento en sí, y puede realizar cualquier lógica adicional deseada.

El operador `tap` ejecuta la función de efecto especificada para cada elemento emitido por el observable. La función de efecto puede ser una función con cualquier lógica adicional que desees realizar, como imprimir en la consola, registrar eventos, enviar datos a un servidor, etc. La función de efecto no modifica el elemento en sí, solo realiza acciones adicionales sobre él.

Aqui su grafica de canicas:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7p4jaqleikj3m53w4v5t.png)


```js
const numeros$ = of(1, 2, 3, 4, 5); // Observable que emite números

numeros$.pipe(
  tap(numero => console.log(`Número emitido: ${numero}`)) // Imprime en la consola cada número emitido
).subscribe();

```
El resultado de este código sería imprimir en la consola: Número emitido: 1, Número emitido: 2, Número emitido: 3, Número emitido: 4, Número emitido: 5, registrando cada número emitido por el observable.

Es importante tener en cuenta que tap no modifica los elementos emitidos por el observable. La función de efecto se ejecuta en paralelo con la emisión de los elementos, sin modificarlos. Si deseas modificar los elementos emitidos, deberás utilizar otros operadores de transformación de datos en combinación con tap.

```js
const numeros$ = of(1, 2, 3, 4, 5); // Observable que emite números

numeros$.pipe(
  tap(x => console.log),
  map(val => val * 10)
).subscribe(val => console.log)
```
El resultado seria 10, 20, 30, 40, 50

## reduce
El operador `reduce` es un operador de transformación que permite reducir una secuencia de valores en un solo valor, Este operador recibe una función de acumulación como argumento y aplica dicha función a los valores emitidos por la secuencia de entrada.

La función de acumulación toma dos argumentos: el acumulador y el valor actual emitido por la secuencia de entrada. El acumulador es el valor acumulado hasta el momento, mientras que el valor actual es el valor emitido por la secuencia en ese instante. La función de acumulación debe devolver un valor que se usará como el nuevo valor del acumulador.

La forma general del operador reduce en rxjs es la siguiente: 

```js
reduce(accumulator: function, seed?: any): Observable
```

El argumento `accumulator` es la función de acumulación que se aplicará a los valores emitidos por la secuencia. El argumento `seed` es un valor opcional que se utilizará como el valor inicial del acumulador. Si se proporciona `seed`, la función de acumulación se aplicará a `seed` y al primer valor emitido por la secuencia. Si no se proporciona `seed` la función de acumulación se aplicará al primer y segundo valor emitidos por la secuencia.
El operador reduce devuelve un `Observable` que emite un solo valor: el resultado final de la acumulación. Este valor se emite cuando la secuencia de entrada se completa.

Grafica de canicas:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t14wm9wbjn2kpuca4ha4.png)

Aquí hay un ejemplo: 

```js
import { of } from 'rxjs';
import { reduce } from 'rxjs/operators';

const source = of(1, 2, 3, 4, 5);

const example = source.pipe(
  reduce((acc, curr) => acc + curr)

example.subscribe(console.log) // salida: 15
```

En el ejemplo anterior, creamos un `Observable` que emite los valores 1, 2, 3, 4, 5. Luego, aplicamos el operador `reduce` con una función de acumulación que suma los valores. El resultado final de la acumulación es 15, que se emite cuando la secuencia de entrada se completa.


## scan
El operador `scan` es un operador de transformación que es similar al operador `reduce`, pero en lugar de emitir un solo valor al final de la secuencia, emite un valor acumulado en cada paso de la secuencia.

La función de acumulación utilizada en `scan` es similar a la utilizada en `reduce` ya que toma dos argumentos: el acumulador y el valor actual emitido por la secuencia de entrada. La diferencia es que la función de acumulación devuelve el valor acumulado en lugar de devolver el valor que se usará como el nuevo valor de acumulador. En otras palabras `scan` emite el valor acumulado después de aplicar la función de acumulación a cada valor de la secuencia de entrada.

la forma general del operador `scan` es la siguiente:

```js
scan(accumulator: function, seed?: any): Observable
```
El argumento `accumulator` es la función de acumulación que se aplicará a los valores emitidos por la secuencia. El argumento `seed` es un valor opcional que se utilizará como el valor inicial del acumulador. Si se proporciona `seed`, la función de acumulación se aplicará a `seed` y al primer valor emitido por la secuencia. Si no se proporciona `seed` la función de acumulación se aplicará al primer y segundo valor emitidos por la secuencia.

El operador `scan` devuelve un `Observable` que emite el valor acumulado después de aplicar la función de acumulación a cada valor de la secuencia de entrada.

Esta es su grafica de canicas:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jcua7kc46f6r1gsc99xl.png)


Por ejemplo: 

 ```js
import { of } from 'rxjs';
import { scan } from 'rxjs/operators';

const source = of(1, 2, 3, 4, 5);

const example = source.pipe(
  scan((acc, curr) => acc + curr)

example.subscribe(console.log) // salida: 1, 3, 6, 10, 15
```

En este ejemplo creamos un `Observable` que emite los valores 1, 2, 3, 4, 5 y luego aplicamos el operador `scan` con una función de acumulación que suma los valores. El valor acumulado después de aplicar la función de acumulación a cada valor de la secuencia de entrada se emite a cada paso de la secuencia. Es este caso, la salida es 1, 3, 6, 10, 15.

## take

El operador `take` permite emitir los primero n valores emitidos por la secuencia de entrada. Una vez que se han emitido n valores, la secuencia se completa automáticamente y se detiene.

La sintaxis básica de take es la siguiente:

```js
take(count: number): Oberservable
```

El argumento `count` especifica el número de valores que se deben emitir antes de completar la secuencia.

Esta es su grafica de canicas:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dq6uuw1oh0sg6owwtvbc.png)

Aquí hay un ejemplo de cómo usar el operador `take` en Rxjs


```js
import { interval } from 'rxjs'
import { take } from 'rxjs/operators';

const source = interval(1000);

const example = source.pipe(
  take(5)
);

example.subscribe(console.log) // salida: 0, 1, 2, 3, 4
```
En este ejemplo, creamos un `Observable` que emite un valor cada segundo utilizando el operador `interval`. Luego, aplicamos el operador `take` con un argumento de 5, lo que significa que solo se emitirán los primeros 5 valores emitidos por la secuencia. La salida del `subscribe` es 0, 1, 2, 3, 4.

EL operador `take` también se puede combinar con otros operadores de rxjs, como `filter`, `map`, `mergeMap`, etc. para manipular y limitar los valores emitidos por la secuencia de entrada.