localStorage y sessionStorage

Una aplicación Angular cuenta con dos sistemas de almacenamiento global de datos. El objetivo de estos sistemas es mantener uno o más datos de forma persistente durante todo el ciclo de vida de la aplicación, incluso aunque se recargue la página.

Estos sistemas son útiles en gran cantidad de situaciones. Un ejemplo muy claro son aquellas aplicaciones que requieren, en todo o en parte, que el usuario esté autenticado. El token de autenticación se almacena mediante alguno de estos sistemas, y cualquier componente de cualquier módulo puede verificar la autenticación del usuario. El tema de la autenticación es algo específico que no vamos a tratar en este artículo, pero si aprenderemos que son y como funcionan localStorage y sessionStorage.

Veremos que son extremadamente fáciles de usar, y que, según las necesidades de nuestra aplicación, nos facilitan muchísimo las cosas. El comportamiento de estos sistemas puede compararse (salvando las diferencias), al uso de cookies o de sesiones.

localStorage

El mecanismo localStorage permite almacenar uno o más datos durante el ciclo de vida de la aplicación… y más aún. Aunque cierres el navegador y vuelvas a abrirlo y cargar la aplicación, los datos que almacenaste permanecen allí. Este mecanismo cuenta con tres métodos:

setItem('nombre', 'valor'). Permite almacenar el valor en la variable nombre.

getItem('nombre'). Permite recuperar el valor que hay almacenado en la variable nombre. Si no hay ninguno, devuelve null.

removeItem('nombre). Permite eliminar del localStorage la variable nombre.

Supongamos, hipotéticamente, el caso que mencionábamos de la autenticación de un usuario. Una vez pasado el proceso de autenticación, se obtiene un token que identifica al usuario. Podemos almacenarlo en el localStorage, inmediatamente tras la autenticación correcta, con una linea similar a la siguiente:

localStorage.setItem ('UserToken', tokenObtenido);

donde tokenObtenido es el token que se ha obtenido de la autenticación. A partir de ese momento, en cualquier componente donde se requiera que el usuario esté autenticado podemos usar una línea como la siguiente:

tokenParaComprobar = localStorage.getItem('UserToken');

Si la autenticación fué correcta, en tokenParaComprobar se almacenará el valor del token, y podremos mostrarle el contenido del componente al usuario. Si no fué correcta, en tokenParaComprobar se almacenará el valor null, y redireccionaremos al usuario a un componente donde se le informe de que tiene el acceso prohibido.

Este sistema tiene la característica (que puede ser una ventaja o un inconveniente) de que si el usuario cierra el navegador y y él mismo u otra persona lo abre después, los valores almacenados en localStorage permanecen intactos. Así pues, otro usuario podría entrar en la aplicación con el token del primero. Sin embargo, podemos añadir un botón de cierre de sesión que ejecute lo siguiente:

localStorage.removeItem('UserToken');

Esto eliminaría de la memoria del navegador la variable UserToken. Después, podríamos redireccionar al usuario al HomeComponent, o donde quisiéramos.

En localStorage puedes almacenar todos los datos que quieras, hasta un máximo de 2 Mb que te permiten los navegadores. Eso es suficiente para cubrir cualquier necesidad de cookies. Algunos navegadores te permiten almacenar hasta 5Mb, pero es mejor contar siempre con el menor límite, ya que no sabes que navegador tendrá tu usuario.

Una limitación que tiene localStorage (lo llamamos limitación pero, en realidad, sólo es una característica que debemos conocer) es que no almacenan correctamente objetos JSON. Si quieres almacenar un objeto, primero debes serializarlo con JSON.parse().

sessionStorage

Este mecanismo funciona igual que el anterior, y cuenta con los mismos métodos. La diferencia es que si cierras el navegador y vuelves a abrirlo, los valores almacenados han desaparecido, lo que es mejor a efectos de seguridad. Por lo demás, todos los detalles de funcionamiento son iguales a los de localStorage.

UN EJEMPLO DE USO

Vamos a seguir jugando con nuestro CRUD de usuarios. Lo que vamos a hacer es que, si en algún momento, se pasa por el formulario de edición de un usuario, almacenaremos su nombre en una variable, con sessionStorage (como te he comentado, aporta mayor seguridad, ya que los datos se borran de la memoria del navegador cuando este se cierra). Para ello, nos vamos a la lógica de MemberFormComponent. Si pasamos por el método que lee los datos de un usuario (es decir, si hemos entrado en edición), añadiremos la siguiente línea:

sessionStorage.setItem('LastEditedName', this.nombre);

En el código de member-form.component.ts que te dejo para descargar al final de este artículo, es la línea 108 del listado.

En la lógica de AppComponent (app.component.ts) tenemos lo siguiente:

Observa la línea resaltada (la 14), en la que recuperamos el valor del nombre del último usuario editado. En el próximo artículo hablaremos del método doCheck(). De momento, haz un acto de fé y creéte que debe estar ahí.

Recuperamos el valor del nombre del último usuario que hemos editado (incluso si, finalmente no lo hemos cambiado; basta con que hayamos pasado por su ficha de edición) en el AppComponent, porque es el componente principal de la aplicación o, como si dijéramos, el padre de todos los componentes. De este modo, podemos contar con este dato en cualquier componente mediante el adecuado uso de @Input. Yo he decidido (esto es una cuestión de diseño de la aplicación, es decir, de criterio personal), que el nombre del último usuario editado lo mostraré en la cabecera (HeaderComponent). Sin embargo, podría mostrarlo donde me pareciera oportuno, porque como en cualquier componente se carga AppComponent, siempre tendré este dato disponible.

Ahora debo modificar app.component.html para que el valor recuperado con el nombre, que está en la variable lastEdited pueda pasar a HeaderComponent. Esto es muy simple. Ya hemos visto algún ejemplo en el curso introductorio de Angular 5, y el sistema no ha cambiado en esta versión (bien 😆 ):

Como ves, es un simple binding a una propiedad que he creado con el nombre lastName. En la lógica de la cabecera (header.component.ts) recupero esa variable mediante @Input, así:

Ya sólo nos falta comprobar, en la vista de la cabecera, si el valor de lastName es null (en cuyo caso no mostraremos nada), o si tiene algún valor, para mostrar el mensaje deseado. El código de header.component.html queda así:

Y ya lo tenemos. Carga tu aplicación en el navegador, vete a la lista de usuarios, y pulsa el botón de edición de cualquiera de ellos. Verás que, a partir de ese momento, el nombre aparece como el último editado, incluso aunque no cambies nada. Si ahora te mueves por cualquier parte de la aplicación, verás que el mensaje permanece. Sin embargo, dado que estamos usando sessionStorage, en lugar de localStorage, cuando cierres el navegador y vuelvas a abrirlo el mensaje habrá desaparecido.

CONCLUYENDO

En este enlace puedes descargar la aplicación en su estado actual. Como ejercicio práctico (y esto lo dejo para que lo hagas tú, a fin de ir experimentando) puedes hacer que si, finalmente, cambias el nombre del usuario, también se actualice en el mensaje que se muestra en la cabecera. Vaaaale, no seré malo. En el próximo artículo te dejaré la aplicación con esto resuelto pero, de momento, intenta hacerlo tú. Nos vemos en el siguiente artículo.

   

Deja un comentario