Conoce cómo llevar la aplicación Platzi Movies al siguiente nivel utilizando React.js. La propuesta es transformar una aplicación ya existente, construida previamente con JavaScript en su versión Vanilla, en una moderna aplicación basada en React. Este paso no solo mejorará tu habilidad técnica, sino que también te permitirá comprender conceptos de navegación avanzada con JavaScript moderno. Prepárate para aprovechar las ventajas de React y React Router, dos herramientas fundamentales en el desarrollo web actual.
¿Qué elementos debe incluir la nueva versión de Platzi Movies?
Para transformar efectivamente Platzi Movies usando React, es esencial mantener las características existentes de la aplicación. Estas incluyen:
Navegación Intuitiva: La aplicación debe permitir navegar de manera fluida entre distintos componentes, aún más integrada gracias a React Router. Esto implica utilizar rutas para presentar diferentes secciones como películas en tendencias, búsquedas y filtros por categorías.
Rutas Personalizadas: Anteriormente, el proyecto utilizaba un sistema de routing artesanal basado en hash. Ahora, es tu misión replicar estas rutas utilizando las poderosas capacidades de React Router para ofrecer una experiencia de usuario optimizada.
Infinite Scrolling: Este comportamiento, ya presente en la versión original, permite cargar más contenido a medida que el usuario se desplaza, mejorando la interacción y la carga dinámica de datos.
¿Cómo implementar React Router en la aplicación?
React Router es una librería esencial para gestionar las rutas de tu aplicación React. Al usarla, podrás controlar fácilmente la navegación entre componentes sin recargar la página, mejorando la eficiencia y ofreciendo una experiencia más moderna. He aquí un ejemplo básico de cómo configurar y utilizar React Router:
Modulariza tu Código: Una de las mejores prácticas en React es dividir tu aplicación en componentes reutilizables. Esto no solo reduce la complejidad del código, sino que también facilita la escalabilidad del proyecto.
Mantén un Estado Global: Considera el uso de contextos o soluciones como Redux para mantener el estado global de tu aplicación, especialmente si manejas datos compartidos entre diversos componentes.
Despliega tu Aplicación: Una vez terminado el clon, es recomendable desplegar la aplicación. Puedes elegir plataformas como Vercel o Netlify. Publicar tu proyecto no solo aumentará su visibilidad, sino también proporcionará un valioso portafolio para futuras oportunidades.
Desarrollar una aplicación moderna utilizando React representa un avance significativo en tu trayectoria como desarrollador web. Este proyecto te permitirá practicar con herramientas y técnicas de última generación, preparando tu perfil profesional para los desafíos actuales. Comparte tus avances, ten presente que el aprendizaje continuo es clave para el éxito en el mundo del desarrollo. ¡Adelante, el límite lo pones tú!
Ya lo tenía planeado :eyes: en un futuro voy a trabajar a full mi platzi movies con muchas más herramientas. TMDB tiene una gran API, muy recomendada para proyectos profesionales.
También tenía pensado recrear Platzi Movies con lo aprendido de React, ¡y sorpresa!, es un reto de este curso.
.
El archivo src/index.css contienes solo los estilos compartidos entre toda la aplicación. Se pueden ver más a detalle en el repositorio de GitHub correspondiente.
.
/* General */*{ box-sizing: border-box;}:root {--purple-light-1: #fbfafb;--purple-light-2: #eeeaf2;--purple-medium-1: #aa83c8;--purple-medium-2: #8b48bf;--purple-medium-3: #5c218a;--purple-dark-1: #3e0f64;--purple-dark-2: #2a0646;--yellow: #eecc75;--green: #cad297;--aqua: #b7eac5;--lightBlue: #a2eee5;--darkBlue: #8ea2ea;--red: #f09d9d;--font-family-titles:"Dosis", sans-serif;--font-family-text:"Red Hat Display", sans-serif;--font-weight-title1:800;--font-weight-title2:700;--font-weight-text1:400;--font-weight-text2:500;}html { background-color:var(--purple-medium-3);}// Otros estilos/* Shared */.header-container,.trendingPreview-header,.categoriesPreview-container,.liked-header {padding:0 24px;}// Más estilos/* Navigation */.inactive{display: none !important;}@keyframes loading-skeleton {0%,100%{opacity:100%;}50%{opacity:0%;}}
.
En el archivo App.js es donde implementamos nuestro HashRouter.
.
.
Cada uno de estas rutas contiene un archivo index.js que es el componente o página que vamos a renderizar dependiendo de la ruta a la que vamos a acceder.
.
Dentro de hook tenemos a nuestros custom hooks.
.
.
Dentro de componentes se encuentran los componentes generales que conforman las páginas o rutas en routes.
.
.
Cada uno de estos componentes contiene un archivo index.js y su correspondiente hoja de estilos.
.
A continuación mostraremos algunos de los archivos más importantes de la aplicación.
.
Omitimos la explicación de las hojas de estilos porque simplemente se movieron los estilos hacia los componentes pertinentes. Sin embargo, estas se pueden ver más a detalle en el repositorio de GitHub correspondiente.
.
.
El hook useTMDBApi facilita la obtención de datos de la API de The Movie Database (TMDB) desde un componente React. Acepta un endpoint y parámetros opcionales params, construye la url de la solicitud y administra el estado de la carga, los datos, el error y la página máxima maxPage para poder hacer un control sobre la paginación. Utiliza useEffect para realizar la solicitud cuando cambia la URL, actualizando los estados correspondientes según el resultado de la solicitud. Devuelve un objeto con los datos obtenidos, el estado de carga, el error y el número máximo de páginas disponibles en la respuesta.
.
El react hook useObserver.
.
.
El hook useObserver utiliza la API IntersectionObserver para observar si un elemento del DOM es visible en la ventana del navegador (viewport). Cuando el elemento se vuelve visible, ejecuta una función de callback. El hook devuelve una referencia elementRef que debe asignarse al elemento del DOM que se quiere observar. Además, limpia el observador cuando el componente se desmonte o cuando cambian las dependencias.
.
El react hook useLocalStorage.
.
.
El hook useLocalStorage gestiona el estado sincronizado con el almacenamiento local del navegador localStorage. Inicializa el estado con un valor almacenado en localStorage o un valor inicial proporcionado initialState. Proporciona funciones para obtener, establecer y agregar elementos al almacenamiento local, asegurando que las actualizaciones en localStorage se reflejen en el estado del componente. Además, establece el valor inicial en localStorage si no está presente. El hook devuelve el estado actual item y las funciones para interactuar con el almacenamiento local.
.
El hook useLikedMovies.
.
.
El hook useLikedMovies gestiona una lista de películas favoritas almacenadas en localStorage. Utiliza el hook useLocalStorage para inicializar, agregar y establecer películas en la lista de favoritos bajo la clave "liked_movies". Proporciona una función likeMovie que añade una película a la lista de favoritos si no está ya en ella, o la elimina si ya está presente. Este hook devuelve la lista de películas favoritas likedMovies y la función likeMovie para actualizar esta lista.
.
El hook useLazyLoading.
.
.
El hook useLazyLoading permite la carga diferida de imágenes en una lista de elementos items. Utiliza una referencia mutable imgRefs para almacenar referencias a las imágenes y la API IntersectionObserver para observar cuándo las imágenes se vuelven visibles en la ventana del navegador (viewport). Cuando una imagen se vuelve visible, se carga su URL desde un atributo "data-img", y si la URL termina en "null", se reemplaza con una imagen de error. Una vez cargada la imagen, se deja de observar. El hook devuelve la referencia de imágenes imgRefs que debe asignarse a cada imagen en el componente que utiliza este hook.
.
.
El componente HomePage combina varios componentes para crear la página de inicio de la aplicación. Utiliza el hook useTMDBApi para obtener datos de categorías y tendencias de películas desde la API de TMDB, y el hook useLikedMovies para gestionar las películas favoritas. Renderiza los componentes Header, TrendingPreview, CategoriesPreview, LikedMovies y Footer, pasando los datos obtenidos y las funciones necesarias como props. Muestra un listado de películas en tendencia, categorías de películas y las películas favoritas del usuario.
.
La página de CategoryPage.
.
.
El componente CategoryPage muestra películas basadas en una categoría específica seleccionada por el usuario. Utiliza hooks de React y hooks personalizados como useTMDBApi para obtener los datos de las películas por categoría y useLikedMovies para gestionar las películas favoritas. Los datos se actualizan y almacenan en el estado local utilizando useState y useEffect. Utiliza el componente GenericList para mostrar las películas y permite cargar más películas al desplazarse hacia abajo mediante una función de paginación.
.
La página de MovieDetailPage.
.
.
El componente MovieDetailPage muestra los detalles de una película seleccionada, así como las recomendaciones de películas relacionadas. Utiliza useParams para obtener el ID de la película de la URL, y hooks personalizados como useTMDBApi para obtener los datos de la película y las recomendaciones desde la API de TMDB. También utiliza useLikedMovies para gestionar las películas favoritas. Renderiza el componente Header con la imagen del póster de la película y el componente MovieDetail para mostrar los detalles y las películas relacionadas.
.
La página de NotFoundPage.
.
.
El componente SearchMoviePage permite a los usuarios buscar películas utilizando una barra de búsqueda. Utiliza useLocation y useSearchParams para obtener la consulta de búsqueda desde la URL o el estado de la navegación. Almacena los resultados de la búsqueda y la página actual en el estado local utilizando useState. Utiliza useTMDBApi para obtener datos de la API de TMDB y useLikedMovies para gestionar las películas favoritas. Cuando cambia la consulta de búsqueda, se restablecen los resultados y la página. Renderiza el componente Header y GenericList para mostrar los resultados de la búsqueda y permite la paginación para cargar más resultados.
.
La página de TrendsPage.
.
.
El componente TrendsPage presenta las películas en tendencia del día utilizando la API de TMDB. Utiliza el hook useTMDBApi para obtener datos de las películas en tendencia, manejando el estado de carga y la paginación. También emplea useLikedMovies para gestionar las películas favoritas. Se mantiene el estado local de la página actual y los resultados obtenidos, actualizándose cuando se reciben nuevos datos de la API. El método addNextPage incrementa la página actual para cargar más resultados. El componente renderiza un Header para la navegación y un GenericList para mostrar las películas en tendencia, permitiendo la interacción con la lista de favoritos y la carga de más contenido conforme el usuario navega.
.
.
El componente Movie representa una tarjeta de película individual con su imagen y un botón para marcarla como favorita. Cuando se hace clic en la tarjeta, se navega a una página de detalles de la película utilizando navigate. La imagen de la película se carga perezosamente utilizando una referencia imgRefs. El botón de favorito cambia su estilo si la película está en la lista de películas favoritas likedMoviesIds y permite agregar o eliminar la película de esa lista con la función likeMovie.
.
El componente MovieList.
.
.
El componente MovieList muestra una lista de películas. Utiliza el hook useLazyLoading para cargar las imágenes de las películas de manera diferida. Navega a los detalles de la película cuando se hace clic en una tarjeta de película y permite marcar o desmarcar películas como favoritas. Si no hay películas para mostrar, muestra un loading skeleton de la lista de películas.
.
El componente Category.
.
.
El componente Category muestra una lista de categorías de películas. Cada categoría tiene un título que, al hacer clic, navega a una página de lista de películas filtrada por esa categoría usando useNavigate. Si no hay categorías disponibles, muestra un loading skeleton.
.
El componente LikedMovies.
.
importReactfrom"react";import{MovieList}from"../MovieList";functionLikedMovies({ likeMovie, likedMovies }){return(<sectionid="liked"className="liked-container"><divclassName="liked-header"><h2className="liked-title">Favorite movies</h3></div><articleclassName="liked-movieList">{likedMovies ?(<MovieListmovies={likedMovies}likeMovie={likeMovie}likedMovies={likedMovies}/>):(Array(3).fill().map((_, index)=>(<divclass="movie-container"><imgkey={index}src="https://image.tmdb.org/t/p/w300/adOzdWS35KAo21r9R4BuFCkLer6.jpg"class="movie-img"alt="Nombre de la película"/></div>)))}</article></section> );
}
export { LikedMovies };
.
El componente LikedMovies muestra una lista de películas que han sido marcadas como favoritas. Utiliza el componente MovieList para renderizar las películas favoritas, pasando la función likeMovie y la lista de películas favoritas como props. Si no hay películas favoritas, muestra un estado de carga con imágenes de películas por defecto.
.
El componente Header.
.
.
El componente Header es un encabezado dinámico que cambia su contenido y estilo en función de la ruta actual. Utiliza hooks de React Router para gestionar la navegación y los parámetros de búsqueda. Muestra un título, una flecha para volver atrás y un formulario de búsqueda, cuyo estado se actualiza según la consulta de búsqueda en la URL. Si moviePoster está presente, establece una imagen de fondo en el encabezado. Este componente se adapta a diferentes páginas como detalles de películas, tendencias, categorías, búsqueda y la página de inicio.
.
El componente TrendingPreview.
.
.
El componente TrendingPreview muestra una vista previa de las películas en tendencia. Incluye un encabezado con un título y un botón que navega a una página de tendencias completa al hacer clic. Utiliza el componente MovieList para renderizar una lista de películas, pasando las películas en tendencia, la función para marcar como favorita y la lista de películas favoritas como props.
.
El componente CategoriesPreview.
.
.
El componente CategoriesPreview muestra una vista previa de las categorías de películas. Incluye un título y utiliza el componente Category para renderizar una lista de categorías. Cada categoría se muestra en un contenedor y permite la navegación a una página de lista de películas filtrada por esa categoría.
.
El componente Footer.
.
importReactfrom"react";import"./Footer.css";functionFooter(){return<footer>Powered by HaroldZS</footer>;}export{Footer};
.
El componente Observer utiliza el hook useObserver para detectar cuándo el div con la clase "observer" entra en el viewport. Este componente toma una función callback que se ejecuta cuando el elemento es visible en la pantalla. Utiliza una referencia observerRef que se pasa al div, activando así la observación y ejecución de la callback cuando el div se intersecta con el viewport.
.
El componente GenericList.
.
.
El componente GenericList muestra listas genéricas de películas usando el componente MovieList. Si está cargando, no muestra las películas; si no, renderiza las películas en páginas sucesivas. Además, utiliza el componente Observer para cargar más contenido cuando el usuario se desplaza al final de la lista. Si no está cargando y aún hay más páginas por cargar, el Observer activa la función addNextPage para obtener más películas.
.
El componente MovieDetail.
.
importReactfrom"react";import"./MovieDetail.css";import{MovieList}from"../MovieList";import{Category}from"../Category";functionMovieDetail({ movieData, relatedMovies, likeMovie, likedMovies, categories,}){return(<><sectionid="movieDetail"className="movieDetail-container">{movieData ?(<><h1className="movieDetail-title">{movieData.title}</h2><spanclassName="movieDetail-score">{movieData.vote_average}</span><pclassName="movieDetail-description">{movieData.overview}</p></> ) : (
<><h1className="movieDetail-title">Deadpool</h2><spanclassName="movieDetail-score">7.6</span><pclassName="movieDetail-description"> Wisecracking mercenary Deadpool battles the evil and powerful
Cable and other bad guys to save a boy's life.
</p></> )}
<articleclassName="categories-list"><Categorycategories={categories}/></article><articleclassName="relatedMovies-container"><h2className="relatedMovies-title">Related movies</h3><divclassName="relatedMovies-scrollContainer"><MovieListmovies={relatedMovies}likeMovie={likeMovie}likedMovies={likedMovies}/></div></article></section></> );
}
export { MovieDetail };
.
El componente MovieDetail muestra los detalles de una película seleccionada, incluyendo su título, puntuación y descripción. También muestra una lista de categorías relacionadas utilizando el componente Category y una lista de películas relacionadas con el componente MovieList. Si no hay datos de la película disponibles, muestra un ejemplo con información de "Deadpool".
.
Esta es la solución que implementé, aunque hay muchos aspectos que todavía puedo mejorar.
Hola a todos, les comparto mi clonación de PlatziMovies.
Despliegue:
Reto: PlatziMovies con React Router
El reto consiste en agarrar el proyecto de Platzi Movies el que construimos en los cursos de Consumo de API REST con Javascript en el práctico y en el profesional, para replicarlo en React JS.
.
Esta aplicación tiene navegación, infinite scrolling, lazy loading entre otras cosas, donde incluso teníamos nuestro propio router hecho a mano para simular un hash router que nos permita realizar navegación a partir de un hash.
.
Llamábamos a location.hash para saber cuando renderizar una ruta u otra. Entonces debes replicar ese mísmo comportamiento pero con React y React Router DOM.