Qué se debe optimizar en el frontend (y qué no)

1

Optimización de Proyectos con APIs REST en JavaScript

2

Optimización de Consumo de API REST en Frontend

3

Uso del Inspector de Elementos y Network en Navegadores

Quiz: Qué se debe optimizar en el frontend (y qué no)

Optimización de imágenes

4

Estrategias de Pantallas de Carga: Spinners vs Skeletons

5

Implementación de Pantallas de Carga con CSS y HTML

6

Implementación de Intersection Observer para Lazy Loading en Imágenes

7

Implementación de Lazy Loading con Intersection Observer

8

Manejo de Errores y Lazy Loading en Imágenes de Aplicaciones Web

Quiz: Optimización de imágenes

Paginación

9

Comparación: Paginación vs. Scroll Infinito en Aplicaciones Web

10

Implementación de Botón para Cargar Más con Paginación API

11

Scroll Infinito en Aplicaciones Web: Implementación y Mejores Prácticas

12

Implementación de Límite en Infinite Scrolling con APIs

13

Implementación de Closures en Paginación Infinita con JavaScript

Quiz: Paginación

Almacenamiento local

14

Almacenamiento Local con Local Storage en JavaScript

15

Maquetación y Estilos para Sección de Películas Favoritas

16

Uso de LocalStorage para Guardar y Recuperar Datos en JavaScript

17

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

Quiz: Almacenamiento local

Bonus

18

Internacionalización y Localización en Aplicaciones Web

19

Despliegue Seguro de Aplicaciones Web y Protección de API Keys

Próximos pasos

20

Optimización de Aplicaciones Frontend con APIs REST y JavaScript

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Implementación de Botón para Cargar Más con Paginación API

10/20
Recursos

¿Cómo implementar la paginación usando un botón de carga?

A medida que navegamos por aplicaciones con gran cantidad de datos, es crucial optimizar la forma en que estos se cargan, tanto para mejorar la experiencia del usuario como para reducir el consumo de recursos. Esta guía profundiza en cómo implementar un botón de carga para manejar la paginación de manera efectiva en una aplicación web.

¿Cómo crear un botón de carga más?

Para comenzar con nuestra implementación, es esencial crear un botón que permita a los usuarios cargar más elementos. Este botón actúa como un paso intermedio antes de implementar el scroll infinito.

let buttonLoadMore = document.createElement('button');
buttonLoadMore.innerText = 'Cargar Más';
document.querySelector('.genericSection').appendChild(buttonLoadMore);

¿Cómo funciona el evento click en el botón de carga?

Una vez que tenemos nuestro botón, es crucial definir su comportamiento al ser presionado. Este es el punto donde conectamos el botón con nuestra lógica de paginación, permitiendo cargar más datos desde la API.

buttonLoadMore.addEventListener('click', function() {
  // Función encargada de cargar la siguiente página
  getPaginatedTrendingMovies();
});

¿Cómo configurar la función para un consumo paginado de la API?

Es vital diferenciar el consumo paginado de la API del consumo tradicional. Esto se consigue agregando parámetros en la URL para solicitar diferentes páginas.

async function getPaginatedTrendingMovies() {
  const response = await axios.get('URL_DE_LA_API', {
    params: {
      page: currentPage // Aquí, currentPage es una variable dinámica que determina qué página cargar
    }
  });
  createMovies(response.data.results, { lazyLoad: true, clean: false });
  currentPage++; // Incrementa la página para la siguiente solicitud
}

¿Cómo manejar el lazy load y el clean como un solo parámetro?

Tener múltiples parámetros en llamadas de función puede ocasionar desorden. Aquí es donde los "parametros como objetos" ofrecen una solución elegante y organizada.

function createMovies(movies, { lazyLoad = true, clean = true }) {
  if (clean) {
    // Lógica para limpiar contenedor
  }
  // Lógica para crear e insertar películas
}

¿Cómo optimizar el proceso para next steps con un scroll infinito?

Aunque el botón de carga es útil, el objetivo final es implementar un scroll infinito que cargue automáticamente más contenido a medida que el usuario navega. Al establecer la base con un botón, sentamos las bases para transformar este evento en un scroll, mejorando así la interacción sin requerir intervención manual continua.

Invitamos a los estudiantes a explorar cómo adaptar el código para que cada clic elimine el botón anterior. Implementar esto puede ser un excelente reto para acelerar su aprendizaje y avanzar hacia una aplicación completamente dinámica.

Aportes 17

Preguntas 1

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Mi solución:
Decidí hacer todo en una misma función para evitar el código repetido

	async function getTrendingMovies(page = 1){
    const { data } = await api('/trending/movie/day', {
        params: {
            page,
        }
    });

    const movies = data.results;

    movieContainer(movies, genericSection, {
        lazy: true,
        clean: page == 1
    });

    const btnLoadMore = document.createElement('button');
    btnLoadMore.innerText = "Load more";
    btnLoadMore.addEventListener('click', () => {
        btnLoadMore.style.display = 'none';
        getTrendingMovies(page + 1);
    });
    genericSection.appendChild(btnLoadMore); 
}

No se compliquen tanto la vida con otra función, puede reutilizar la misma solo añadiendo al boton un addEventListener que llame nuevamente a la misma función, solo que le deben agregar a la función un parámetro por defecto que indique la página.

Alli tambien agregue lo de quitar el botón viejo cuando se le da click, para que solo quede el nuevo al final.

si recargamos la primera es Spiderman después… LA penúltima es ETERNALS ajjajajaja

Yo lo que hice y me pareció sencillo es lo siguiente:

La mejor forma de eliimiinar el contenido de una sección es hacerlo desde el fiile navigation.js así solo lo liimpia cuando es la primera vez que entremos allí, luego cuando agreguemos más pelíiculas no eliimina las anteriores.
.
.
Sii no quieren dupliciar la función de obtener datos de forma paginada pueden modiificar la misma función agregando parámetros opcionales con valores pordefecto para que no rompa nada de la siguiiente manera

const getTrendingMovies = async (nextCollection= false, page = 1) => {
	const dinPage = nextCollection ? page + 1 : page;
	...
	// creamos el botón
	const btnLoadMoreTrendingMovies = createButtonLoadMore(genericSectionUpdate);
	btnLoadMoreTrendingMovies.addEventListener('click', () => {
            btnLoadMoreTrendingMovies.remove();
            trendingMovies(true, dinPage);
        });
}

Sii observamos si la funciión se ejecuta normalmente con los valores pordefecto, se agregará la página 1 y agregará el botón, al detectar el evento click el botón, entonces llamamos a la misma función pero esta vez le deciimos que si es paginado y le pasamos el número de página que antes estaba para que la próxima vez le adiicione la siguiente. Por lo que veo, esta misma función se puede ir modificando a futuro decidiendo si queremos paginación con botón más o scroll infinito sin necesidad de crear más funciones.
.
Espero que les guste mi propuesta!
.
Commit actual: Click aquí

Commit con los cambios: Click aquí

Usé el truco que hicieron algunos para poner en True comparando con la página 1 y además utilicé un closure para que no ande volando la variable page.

function getTrendingMoviesScroll(){
page = 1
  async function getPaginatedScroll(){
    console.log(page);
    const {data} = await api('trending/movie/day',{
      params:{
        page: page
      },
    });
    const movies = data.results;
    createMovies(movies,genericSection,{clean:page==1});
    const btnLoadMore = document.createElement('button');
    
    btnLoadMore.innerText = 'Cargar más';
    btnLoadMore.addEventListener('click',getPaginatedScroll);
    genericSection.appendChild(btnLoadMore);
    page++;
  }
  return getPaginatedScroll;
}

En el archivo navigation mando entonces a llamár esta función en lugar de la anterior

function trendsPage() {
  console.log('TRENDS!!');

  headerSection.classList.remove('header-container--long');
  headerSection.style.background = '';
  arrowBtn.classList.remove('inactive');
  arrowBtn.classList.remove('header-arrow--white');
  headerTitle.classList.add('inactive');
  headerCategoryTitle.classList.remove('inactive');
  searchForm.classList.add('inactive');

  trendingPreviewSection.classList.add('inactive');
  categoriesPreviewSection.classList.add('inactive');
  genericSection.classList.remove('inactive');
  movieDetailSection.classList.add('inactive');

  headerCategoryTitle.innerHTML = 'Tendencias';
  
  getTrendingMoviesScroll()();
  /* getTrendingMovies(); */
}

Asi es com yo cree el infinite scroll.

async function showTrendsPage() {
    let movies = await apiModule.getTrendingMovies(pageNumber)
    pageNumber++

    let createMovies = new Movies({section: genericSection, movies: movies})
    createMovies.applyMovies({clean: false})


    let btn = document.createElement('button')
    btn.classList.add('genericSection--button')
    btn.innerText = "AGREGAR MAS"
    genericSection.appendChild(btn)
    btn.addEventListener('click', () => {
        showTrendsPage()
        btn.remove()
    })
   
}

Yo saque el boton en una funcion aparte para que cada funcion tenga una propia responsabilidad, y luego de hacer el llamado a la API eliminaba el boton.

Bueno por mi parte pude solucionar el bug del botón repetido con las siguientes 2 líneas en la función “getPaginatedTrendingMovies” antes de las acciones que crean el botón.

  const btnLoadMoreExist = document.querySelector('#btn-load-more');
  genericSection.removeChild(btnLoadMoreExist);

Si no estan usando AXIOS - Recuerden pasar correctamente los Query Parameters
Juan en el video pasa el Query parameter con el simbolo “?”, y eso nos devuelve un error en consola…
La forma correcta de pasar el Query es a traves del simbolo “&”.
La URL que le paseremos a Fetch() sin AXIOS quedaría asi: https://api.themoviedb.org/3/trending/movie/day?api_key=${API_KEY}&page=2`

Es más sencillo llamar a la variable let page = 1 directamente en lugar de llamarlo primero dentro de la función y después dentro de params. por ejemplo:

let pagination = 2

async function getPaginationTrendingMovies() {
    const { data } = await URL_API('/trending/movie/day', {
        params: {
            page: pagination++	// Aquí se hace el incremento directamente
        }
    })
}

Así no tenemos que volver a crear el botón ni mucho menos dejar varios botones sin usar por cada click,

Solución con una linea de código.

Simplemente agregué el removechild al momento de que se ejecuta la fn getPagesTrend (damos click), eso de primeras elimina el botón que acabamos de crear, y ejecuta la fn(getPagesTrend) que crea nuevamente el btn y que al volver a dar click otra vez ejecuta la fn y nuevamente lo elimina y así sucesivamente.
Lo que si hay que declarar el boton por fuera de las funciones para que no de ningún error y para que las 2 funciones entiendan y sepan que se hace referencia al mismo btn.

async function getTrends(){ //FN tendencias
. //llamado api
.
.
		btnLoadmore = document.createElement('button')
    btnLoadmore.innerText= 'Cargar más';
    movieCategory.appendChild(btnLoadmore)
    btnLoadmore.addEventListener('click', getPagesTrend)
}

let btnLoadmore;
let page = 1;

async function getPagesTrend(){  //FN Paginación
    movieCategory.removeChild(btnLoadmore);
.
. //llamado api, creando nuevamente btn
.
}
Para no tener que crear un nuevo boton cada vez que se recarga la página y borrar el anterior, lo que hice fue agregar estilos al boton para que aparezca esté fijo siempre. ```js .btn { position: fixed; z-index: 1; bottom: 50px; } ```
Yo lo hice con un observer, primero para el tema del boton no se este duplicado en el html tener el el cuerpo 2 contenedores 1 para las imgs y el otro para el o boton con eso siempre estara al final y no se duplicara ![](https://static.platzi.com/media/user_upload/image-167496e0-a088-41b2-892c-68c2090d554a.jpg) Luego cuando el observer detecte al final del documento es cuando ejecutamos la funcion ![](https://static.platzi.com/media/user_upload/image-c7c72c99-fc93-4b89-a417-5fb10b11b852.jpg) y bueno como use la misma plantilla para trending como para genre tengo que hacer una validacion para la api pero en este punto fue lo mismo que el profe solo que el restablecer el contenedor a 0 no lo hacia en el generateImgs sino el la misma logica por tanto no fue necesario pasarle mas parametros ![]()![](https://static.platzi.com/media/user_upload/image-b014c2e4-724f-4482-812b-52a54b752085.jpg)
Yo aniadi estas dos lineasen la funcion getPaginatedTrendingMovies para eliminar el boton de carga ```js const oldBtnCarga = document.querySelector('#btnCarga') genericSection.removeChild(oldBtnCarga) ```  const oldBtnCarga = document.querySelector('#btnCarga')  genericSection.removeChild(oldBtnCarga) ![](https://static.platzi.com/media/user_upload/reto%20API-8a8c8767-a4f3-4e21-8374-02c58190a48e.jpg)
No hay una mejor forma, o estratégia. Depende que objetivo tengas para tu app

Sé que en JS no es necesario, pero procuro escribir la función que llamo arriba del código. Por si me cambio a otros lenguaje que no tenga Hoisting.