Cómo almacenar datos en caché en Angular con Rxjs

El blog de hoy está inspirado en la redacción y contenido del articulo de mi amigo Dany Paredes, donde nos da grandes tips de interés para acelerar nuestras aplicaciones y mejorar la experiencia del usuario fácilmente

· 4 min de lectura
Cómo almacenar datos en caché en Angular con Rxjs

Cuando construimos una aplicación, algunos datos como el menú y las opciones no cambian con frecuencia. El mejor enfoque es almacenarlo en caché porque cuando el usuario se mueve por la aplicación, los datos al servidor vuelven a impactar la velocidad y la experiencia del usuario.

Rxjs nos proporciona una manera fácil de construir una caché y almacenarla. Dos operadores hacen la magia, share y shareReplay, para evitar obtener los datos cada vez y evitar el cálculo.

Antes de entrar directamente en la parte práctica te compartiré algunos conceptos que desde mi punto de vista son de gran relevancia

Si tu deseas leer esté articulo en Ingles, o quieres conocer un poco más sobre Dany Paredes y sus grandes aportaciones a la comunidad, te invito a que te pases por su blog, y que vayas a leer rápidamente el articulo que tenemos acerca de él.

¿Qué es la caching?


El caching también conocido como La caché se desarrolló inicialmente para reducir el tiempo de acceso entre la CPU y la RAM.

Se utiliza principalmente para almacenar datos a los que probablemente se accederá en un tiempo cercano (segundos, minutos u horas después).

Así que si te preguntas por qué las cosas van mucho más rápido la segunda vez que recargas algo (refrescar una página), es cuando realmente ves el poder del almacenamiento en caché.

Ejemplo


Tengo una aplicación sencilla con dos rutas, home y about. Home muestra una lista de jugadores de la NBA; además, procesamos los datos construyendo el fullName usando su nombre y apellido.

Cada vez que el usuario se mueve para salir de casa y volver, necesita obtener los datos y realizar el proceso. Debe ser un proceso extenso como el cálculo.

¿Por qué estoy obteniendo los datos de nuevo si no cambia con la frecuencia? Parece que ha llegado el momento de almacenar los datos en caché.

Pero antes de irnos a la práctica entremos un poco en teoría

¿Qué es ShareReplay?

Este operador es una especialización de la repetición que se conecta a un observable de origen y se multiplica a través de un ReplaySubject construido con los argumentos especificados.

Una fuente completada con éxito se mantendrá en la caché del observable shareReplayed para siempre, pero una fuente con errores puede volver a intentarse.

via GIPHY

¿Por qué utilizar shareReplay?


Por lo general, puedes utilizar shareReplay cuando tenga efectos secundarios que no desees que se ejecuten entre varios suscriptores.

También puede ser valioso en situaciones en las que sabes que tendrás suscriptores tardíos a un flujo que necesitan acceder a valores emitidos previamente.

Esta capacidad de reproducir valores en la suscripción es lo que diferencia a share y shareReplay.

Usando shareReplay


Mejoraremos el rendimiento y la respuesta de nuestra app, evitaremos repetir el proceso de construcción de fullName para cada jugador y tendremos una fecha del proceso para ver el tiempo de procesamiento.

shareReplay nos ayuda a almacenar en caché los datos de nuestra app de forma rápida y a reproducir los datos a los nuevos suscriptores.

Añade el operador shareReplay en el flujo de datos, toma los datos de la petición HTTP y los colocas en un buffer para que pueda reproducir la última emisión de mi petición HTTP.

@Injectable()
export class NbaService {
  api = 'https://www.balldontlie.io/api/v1/';

  private teamUrl = this.api + 'players';
  public players$ = this.http.get<any[]>(this.teamUrl).pipe(
    map((value: any) => {
      return value?.data.map((player) => ({
        ...player,
        fullName: `${player.first_name} ${player.last_name}`,
        processed: new Date().toISOString(),
      }));
    }),
    shareReplay(1),
  );

  constructor(private http: HttpClient) {}
}

Perfecto, podemos ver los datos en la página. Usamos el operador de pipe Date para formatear mejor la fecha procesada.

<ul *ngIf="players$ | async as players">
  <li *ngFor="let player of players">
    {{ player.fullName }} {{ player.processed | date: 'medium' }}
  </li>
</ul>

Si navegamos por la aplicación de una página a otra y volvemos a la página de inicio, obtendrá los datos de la caché.

Puedes ver los detalles en la pestaña de red en Chrome

Sí, es muy fácil, ¡tener un caché en nuestra aplicación! Pero, ¿Cómo forzar una actualización?

Actualizar la caché y refrescar los datos


Nuestra caché funciona a las mil maravillas, pero a veces los usuarios quieren forzar la actualización. ¿Cómo podemos hacerlo? ¡Rxjs nos facilita la vida!

Utilizamos un behaviorSubject para ayudar a reaccionar a la acción cuando el usuario quiere actualizar los datos.

Primero, creamos el behaviorSubject de tipo void y un nuevo método updateData() para emitir la acción, creamos una nueva variable apiRequest$ para almacenar la petición HTTP.

Nuestro observable players$ obtendrá el valor del sujeto de comportamiento y canalizará los datos utilizando el operador merge map para fusionar la respuesta HTTP, devolver el observable y añadir el shareReplay.

El código final es el siguiente

 @Injectable()
export class NbaService {
  private _playersData$ = new BehaviorSubject<void>(undefined);
  api = 'https://www.balldontlie.io/api/v1/';

  private teamUrl = this.api + 'players';
  apiRequest$ = this.http.get<any[]>(this.teamUrl).pipe(
    map((value: any) => {
      console.log('getting data from server');
      return value?.data.map((player) => ({
        ...player,
        fullName: `${player.first_name} ${
          player.last_name
        } ${Date.now().toFixed()}`,
      }));
    })
  );

  public players$ = this._playersData$.pipe(
    mergeMap(() => this.apiRequest$),
    shareReplay(1)
  );

  constructor(private http: HttpClient) {}

  updateData() {
    this._playersData$.next();
  }
}

En la página, crear un nuevo botón para llamar al método de servicio y forzar la actualización de los datos desencadenando tu behavior; se puede jugar con la versión final en el ejemplo stackbliz.

Perfecto. Tu puedes ver el código final aquí

Recapitulación

via GIPHY


¡Podemos crear una caché y forzar su actualización fácilmente usando Rxjs, así que es fácil la próxima vez que quieras mejorar la velocidad y la respuesta!

Recomiendo encarecidamente ver algunos vídeos de @deborahk. Ella explica muy bien todo sobre Rxjs y cómo trabajar con los datos.

Composición de datos con RxJS | Deborah Kurata
Recoger, combinar y almacenar en caché los flujos de RxJS para obtener resultados fáciles de usar por Deborah Kurata

El almacenamiento en caché es una opción viable si queremos ahorrar número de peticiones al servidor, especialmente para datos que cambian raramente, como los diarios, semanales y más!

Fuente

Referencias

Plataforma de cursos gratis sobre programación