Gestión de Películas Favoritas con Local Storage en JavaScript

Resumen

Mostrar la lista de películas favoritas en una app con JavaScript implica leer el objeto guardado en localStorage, convertirlo en array y renderizarlo en el DOM. Esta guía explica cómo lograrlo, sincronizar el estado visual de los botones de like y resolver los errores de navegación que aparecen cuando agregas una nueva sección al HTML.

Cómo leo las películas favoritas desde localStorage

La idea es replicar la lógica de funciones como getTrendingMovies o getMoviesBySearch, pero en vez de consumir una API, consumimos localStorage.

Para empezar, creas una función getLikedMovies que invoca a la función likedMoviesList, la cual hace JSON.parse de lo que viene guardado y devuelve un objeto con cada película indexada por su id.

¿Cómo convierto un objeto de localStorage en un array? Usa Object.values(miObjeto). Ese método devuelve un array con todos los valores del objeto, ignorando las llaves, listo para iterarlo o pasarlo a una función de renderizado.

Una vez tienes el array, lo pasas a createMovies junto con el contenedor, el flag de lazy loading y el flag para limpiar el HTML previo:

  • El array de películas viene de Object.values(likedMovies).
  • El contenedor es el nodo likedMoviesListArticle seleccionado con document.querySelector.
  • Lazy loading en true por si la lista crece.
  • Limpieza del contenedor en true para evitar duplicados al recargar.

Un detalle fácil de pasar por alto: al definir el selector en el archivo de nodos, el querySelector necesita el punto inicial para clases (.liked-movies-list) o el # para IDs. Sin ese punto, recibes el clásico error Cannot read properties of null (reading 'innerHTML').

Por qué los botones de like se ven desincronizados al recargar

Cuando recargas la página, los botones de corazón pierden la clase movie-button-liked porque el DOM se reconstruye desde cero. Aunque la información persiste en localStorage, la UI no la refleja hasta que la consultas explícitamente al pintar cada tarjeta.

Cómo sincronizo el estado visual del botón con localStorage

Dentro de la función createMovies, justo donde defines el botón de like, agregas un condicional que pregunta si el id de esa película existe en el objeto que devuelve likedMovieList():

javascript if (likedMovieList()[movie.id]) { movieBtn.classList.add('movie-button-liked'); }

Aquí no usas toggle, porque toggle invierte el estado. Lo que necesitas es solo añadir la clase cuando la película ya esté guardada. El toggle se queda únicamente para el event listener del clic, donde sí queremos alternar.

¿Qué hace Object.values en JavaScript? Recibe un objeto y devuelve un array con todos sus valores, en el orden en que fueron declarados. Es la forma más limpia de iterar valores de un objeto sin tocar las claves.

Cómo arreglo la navegación entre secciones

Al agregar la sección de favoritos al HTML, esta aparece en todas las rutas porque nunca le aplicas la clase inactive. La solución vive en navigation.js.

Primero, declaras el nodo en el archivo de selectores:

  • likedMoviesSection apunta al elemento con id liked.
  • Lo importas en navigation.js junto con el resto.
  • Replicas la misma lógica de add y remove que ya usas para trendingPreviewSection.

La regla práctica: cada vez que trendingPreviewSection recibe classList.remove('inactive') (en homePage), también se lo quitas a likedMoviesSection. Y cada vez que se lo agregas en categoriesPage, movieDetailsPage, searchPage o trendsPage, repites el add('inactive') para favoritos.

Con eso, la sección de películas favoritas solo aparece en el home y desaparece en categorías, búsqueda, tendencias y detalle de película.

Cómo escucho cambios de localStorage en tiempo real

Queda un detalle: si das like desde la página de tendencias sin navegar a otra ruta, la lista de favoritos del home no se actualiza hasta que recargas o cambias de sección. La razón es que getLikedMovies solo se ejecuta cuando se llama a homePage.

La solución es escuchar el evento storage del objeto window. Funciona como cualquier otro event listener:

javascript window.addEventListener('storage', getLikedMovies);

Cada vez que algo cambie en localStorage, el evento se dispara y vuelves a renderizar la lista. La documentación de MDN sobre Storage Event es la referencia recomendada para profundizar.

¿Cuándo se dispara el evento storage en JavaScript? Se dispara cuando otro documento del mismo origen modifica localStorage o sessionStorage. En la misma pestaña que hace el cambio puede no dispararse, así que a veces conviene emitir un evento personalizado tras escribir.

Qué aprendiste sobre persistencia y DOM en esta práctica

Resolver este flujo te entrena en habilidades concretas:

  • Manipulación del DOM con querySelector y respeto a la sintaxis de selectores CSS.
  • Persistencia con localStorage usando JSON.parse y JSON.stringify.
  • Conversión de objetos a arrays con Object.values para reutilizar funciones de renderizado.
  • Control de visibilidad de secciones mediante una clase inactive y event listeners de navegación.
  • Sincronización de estado visual con datos persistidos al cargar la página.

El reto abierto es claro: implementa el event listener de storage para que la lista de favoritos se actualice sin recargar ni navegar. Cuéntame en los comentarios qué nombre le habrías puesto al nodo likedMoviesListArticle y cómo resolviste la actualización en tiempo real.