Cómo implementar el desplazamiento infinito en React

Introducción

Índice
  1. Introducción
  • Prerrequisitos
  • Paso 1: Configuración del proyecto
  • Paso 2 — Implementación onscrollyloadApods
  • Paso 3: agregar una carga inicial y manejo de errores
  • Conclusión
  • El desplazamiento infinito se produce cuando un usuario llega al final de una página y se obtiene y carga contenido nuevo para que el usuario pueda seguir desplazándose en una experiencia relativamente fluida. Esta es una alternativa a otras soluciones de paginación que utilizan páginas numeradas o botones que cargan más contenido.

    Es posible que te hayas encontrado con un desplazamiento infinito en aplicaciones como Instagram. Se te presenta un feed de imágenes y, a medida que te desplazas hacia abajo, aparecen más imágenes una y otra vez hasta que se acaba el contenido que te ofrecen.

    En este tutorial, abordará los dos conceptos claves que permiten que funcione el desplazamiento infinito: detectar cuándo el usuario ha llegado al final de la página y cargar el siguiente lote de contenido para mostrar. Utilizará estos conceptos para crear una visualización de fotografías y vídeos astronómicos.

    Prerrequisitos

    Para completar este tutorial, necesitarás:

    • Un entorno de desarrollo local para Node.js. Sigue Cómo instalar Node.js y crear un entorno de desarrollo local.
    • Este tutorial utilizará la API Astronomy Picture of the Day (APOD) de la NASA. Para fines de demostración, se utilizará DEMO_KEYpara solicitudes, pero es posible que desee registrarse para obtener una clave API si genera muchas solicitudes.

    Este tutorial fue verificado con Node v14.12.0, npmv6.14.8, reactv16.13.1, superagentv6.1.0 y lodash.debouncev2.7.1.

    Paso 1: Configuración del proyecto

    Comience a usar create-react-apppara generar una aplicación React y luego instale las dependencias:

    1. npx create-react-app react-infinite-scroll-example

    Cambiar al nuevo directorio del proyecto:

    1. cd react-infinite-scroll-example

    Para cargar datos desde la API de APOD, utilizará superagent.

    Para eliminar el rebote de los eventos, utilizarás lodash.

    Para agregar superagenty lodash.debouncea su proyecto npmejecutar:

    1. npm install superagent@6.1.0 lodash.debounce@4.0.8

    Ahora, puedes ejecutar la aplicación React:

    1. npm start

    Corrija cualquier error o problema que tenga con su proyecto y acceda a él localhost:3000desde un navegador web.

    Una vez que tenga una aplicación React en funcionamiento, puede comenzar a desarrollar su funcionalidad de desplazamiento infinito.

    Paso 2 — Implementación onscrollyloadApods

    El desplazamiento infinito requiere dos partes clave. Una parte será la comprobación de la posición de desplazamiento de la ventana y la altura de la ventana para determinar si el usuario ha llegado al final de la página. Otra parte será la gestión de la solicitud de información adicional para mostrar.

    Comenzamos a crear un InfiniteSpace.jsarchivo:

    1. nano src/InfiniteSpace.js

    Construye tu InfiniteSpacecomponente:

    Fuente/InfiniteSpace.js

    import React from 'react';import request from 'superagent';import debounce from 'lodash.debounce';class InfiniteSpace extends React.Component {  constructor(props) {    super(props);    this.state = {      apods: [],    };  }  render() {    return (      div        h1Infinite Space!/h1        pScroll down to load more!!/p      /div    )  }}export default InfiniteSpace;

    El componente de desplazamiento infinito se basa en un onscrollevento que comprobará si el usuario se ha desplazado hasta el final de la página. Al llegar al final de la página, el evento intentará cargar contenido adicional.

    Al vincular eventos, especialmente eventos de desplazamiento, es una buena práctica eliminar el rebote de los eventos. La eliminación del rebote se produce cuando solo se ejecuta una función una vez que ha transcurrido una cantidad de tiempo específica desde la última llamada.

    La eliminación de rebotes mejora el rendimiento para el usuario al limitar la frecuencia con la que se activa un evento y también ayuda a aliviar la tensión de los servicios que pueda estar llamando desde el controlador de eventos.

    Fuente/InfiniteSpace.js

    class InfiniteSpace extends Component {  constructor(props) {    super(props);    this.state = {      apods: [],    };    window.onscroll = debounce(() = {      const {        loadApods      } = this;      if (window.innerHeight + document.documentElement.scrollTop === document.documentElement.offsetHeight) {        loadApods();      }    }, 100);  }  // ...}

    Este código establece una iteración antirrebote de 100 milisegundos.

    La loadApodsfunción utilizará superagent's requestpara GETla Imagen Astronómica del Día:

    Fuente/InfiniteSpace.js

    class InfiniteSpace extends Component {  constructor(props) {    // ...  }  dayOffset = () = {    let today = new Date();    let day = today.setDate(-1 * this.state.apods.length);    return new Date(day).toISOString().split('T')[0];  }  loadApods = () = {    request      .get('https://api.nasa.gov/planetary/apod?date=' + this.dayOffset() + 'api_key=DEMO_KEY')      .then((results) = {        const nextApod = {          date: results.body.date,          title: results.body.title,          explanation: results.body.explanation,          copyright: results.body.copyright,          media_type: results.body.media_type,          url: results.body.url        };        this.setState({          apods: [            ...this.state.apods,            nextApod          ]        });      });  }  render() {    // ...  }}

    dayOffsetSe utilizará una función para calcular la Imagen Astronómica del Día anterior.

    Este código asignará la respuesta de APOD para almacenar los valores para date, title, explanation, copyright, media_typey url.

    Los datos que se han cargado se agregarán a una matriz en el estado del componente y se iterarán en el rendermétodo del componente.

    Para verificar que las dos piezas funcionan juntas, rendericemos la respuesta:

    class InfiniteSpace extends Component {  // ...  render() {    return(      div        h1Infinite Space!/h1        pScroll down to load more!!/p        {apods.map(apod = (          React.Fragment key={apod.date}            hr /            div              h2{apod.title}/h2              {apod.media_type === 'image'                 img                  alt={`NASA APOD for {apod.date}`}                  src={apod.url}                  style={{                    maxWidth: '100%',                    height: 'auto'                  }}                /              }              {apod.media_type === 'video'                 iframe                  src={apod.url}                  width='640'                  height='360'                  style={{                    maxWidth: '100%'                  }}                /iframe              }              div{apod.explanation}/div              div{apod.copyright}/div            /div          /React.Fragment        ))}        hr /      /div    );  }}

    Este código mostrará un imgo un iframedependiendo del media_typeAPOD.

    En este punto, puedes modificar tu Appcomponente para importarlo InfiniteSpace. Abrir App.js:

    1. nano src/App.js

    Y reemplace el contenido generado por Create React App con el InfiniteSpacecomponente:

    fuente/App.js

    import React from 'react';import InfiniteSpace from './InfiniteSpace';function App() {  return (    div className="App"      InfiniteSpace /    /div  );}export default App;

    En este punto, puedes ejecutar tu aplicación nuevamente:

    1. npm start

    Corrija cualquier error o problema que tenga con su proyecto y acceda a él localhost:3000desde un navegador web.

    Si se desplaza hacia abajo en la altura de la página web, se activarán las condiciones para que onscrollse active el evento loadApodsy debería aparecer un nuevo APOD en la pantalla.

    Con estas dos piezas para el desplazamiento infinito en su lugar, se ha establecido la mayor parte del InfiniteSpacecomponente. Agregar una carga inicial y un control de errores ayudará a que sea más robusto.

    Paso 3: agregar una carga inicial y manejo de errores

    Actualmente, InfiniteSpaceno carga ningún APOD hasta que se cumplan las condiciones del onscrollevento. También hay tres situaciones en las que no querrás cargar APOD: si no hay más APOD para cargar, si está cargando un APOD en este momento y si se produce un error. Abordemos estos problemas.

    Primero, revise InfiniteSpace.js:

    1. nano src/InfiniteSpace.js

    Luego, utilice componentDidMount()para una carga inicial:

    Fuente/InfiniteSpace.js

    class InfiniteSpace extends Component {  constructor(props) {    // ...  }  componentDidMount() {    this.loadApods();  }  dayOffset = () = {    // ...  }  loadApods = () = {    // ...  }  render() {    // ...  }}

    Agregue error, hasMore, y isLoadingal estado para abordar errores y restringir la carga innecesaria:

    Fuente/InfiniteSpace.js

    class InfiniteSpace extends Component {  constructor(props) {    super(props);    this.state = {      error: false,      hasMore: true,      isLoading: false,      apods: []    };    // ...  }  // ...}

    errorse establece inicialmente en false. hasMorese establece inicialmente en true. y isLoadingse establece inicialmente en false.

    Luego, aplica el estado a onscroll:

    Fuente/InfiniteSpace.js

    class InfiniteSpace extends Component {  constructor(props) {    super(props);    this.state = {      error: false,      hasMore: true,      isLoading: false,      apods: []    };    window.onscroll = debounce(() = {      const {        loadApods,        state: {          error,          isLoading,          hasMore        }      } = this;      if (error || isLoading || !hasMore) return;      if (window.innerHeight + document.documentElement.scrollTop === document.documentElement.offsetHeight) {        loadApods();      }    }, 100);  }  // ...}

    Esta verificación se ejecutará de manera anticipada y evitará loadApodsque se invoque en situaciones en las que haya un error, se esté cargando actualmente o no haya APOD adicionales para cargar.

    Luego, aplica el estado a loadApods:

    Fuente/InfiniteSpace.js

    class InfiniteSpace extends Component {  // ...    loadApods = () = { this.setState({ isLoading: true }, () = {    request      .get('https://api.nasa.gov/planetary/apod?date=' + this.dayOffset() + 'api_key=DEMO_KEY')      .then((results) = {        const nextApod = {          date: results.body.date,          title: results.body.title,          explanation: results.body.explanation,          copyright: results.body.copyright,          media_type: results.body.media_type,          url: results.body.url        };        this.setState({          hasMore: (this.state.apods.length  5),          isLoading: false,          apods: [            ...this.state.apods,            nextApod          ],        });      })      .catch((err) = {        this.setState({          error: err.message,          isLoading: false          });      });    });  }  // ...}

    Este código utiliza setState con una función de devolución de llamada pasada como segundo argumento. La llamada inicial a setStateen el loadApodsmétodo establece el valor de isLoadingto truey luego, en la función de devolución de llamada, se carga el siguiente APOD y setStatese lo vuelve a llamar para establecer isLoadingto false.

    Para los fines de nuestro tutorial, hasMorees una comprobación booleana para limitar la cantidad de APOD a 5. En diferentes escenarios, una API puede devolver algún valor como parte de la carga útil que indica si hay más contenido para cargar.

    Si loadApodsencuentra un error, errorse establece err.messageen el catchbloque.

    Luego, aplica el estado a render:

    Fuente/InfiniteSpace.js

    class InfiniteSpace extends Component {  // ...  render() {    const {      error,      hasMore,      isLoading,      apods    } = this.state;    return (      div        {/* ... React.Fragment ... */}        {error           div style={{ color: '#900' }}            {error}          /div        }        {isLoading           divLoading.../div        }        {!hasMore           divLoading Complete/div        }      /div    );  }]

    Esto ahora mostrará mensajes para error, isLoading, y hasMore.

    Cuando todas las piezas estén juntas, InfiniteSpaceverás así:

    Fuente/InfiniteSpace.js

    import React from 'react';import request from 'superagent';import debounce from 'lodash.debounce';class InfiniteSpace extends React.Component {  constructor(props) {    super(props);    this.state = {      error: false,      hasMore: true,      isLoading: false,      apods: []    };    window.onscroll = debounce(() = {      const {        loadApods,        state: {          error,          isLoading,          hasMore,        },      } = this;      if (error || isLoading || !hasMore) return;      if (window.innerHeight + document.documentElement.scrollTop === document.documentElement.offsetHeight) {        loadApods();      }    }, 100);  }  componentDidMount() {    this.loadApods();  }  dayOffset = () = {    let today = new Date();    let day = today.setDate(-1 * this.state.apods.length);    return new Date(day).toISOString().split('T')[0];  }  loadApods = () = {this.setState({ isLoading: true }, () = {    request      .get('https://api.nasa.gov/planetary/apod?date=' + this.dayOffset() + 'api_key=DEMO_KEY')      .then((results) = {        const nextApod = {          date: results.body.date,          title: results.body.title,          explanation: results.body.explanation,          copyright: results.body.copyright,          media_type: results.body.media_type,          url: results.body.url        };        this.setState({          hasMore: (this.state.apods.length  5),          isLoading: false,          apods: [            ...this.state.apods,            nextApod          ],        });      })      .catch((err) = {        this.setState({          error: err.message,          isLoading: false        });      });    });  }  render() {    const {      error,      hasMore,      isLoading,      apods    } = this.state;    return (      div style={{        padding: 10      }}        h1Infinite Space!/h1        pScroll down to load more!!/p        {apods.map(apod = (          React.Fragment key={apod.date}            hr /            div              h2{apod.title}/h2              {apod.media_type === 'image'                 img                  alt={`NASA APOD for {apod.date}`}                  src={apod.url}                  style={{                    maxWidth: '100%',                    height: 'auto'                  }}                /              }              {apod.media_type === 'video'                 iframe                  src={apod.url}                  width='640'                  height='360'                  style={{                    maxWidth: '100%'                  }}                /iframe              }              div{apod.explanation}/div              div{apod.copyright}/div            /div          /React.Fragment        ))}        hr /        {error           div style={{ color: '#900' }}            {error}          /div        }        {isLoading           divLoading.../div        }        {!hasMore           divLoading Complete/div        }      /div    );  }}export default InfiniteSpace;

    Por último, ejecute su aplicación nuevamente:

    1. npm start

    Corrija cualquier error o problema que tenga con su proyecto y acceda a él localhost:3000desde un navegador web.

    Desplácese hacia abajo y su aplicación buscará y mostrará 5 APOD. Todas las piezas para el desplazamiento infinito se han unido.

    Conclusión

    En este tutorial, implementa el desplazamiento infinito en una aplicación React. El desplazamiento infinito es una solución moderna que potencialmente puede ayudar a presentar una gran cantidad de información al usuario final sin tiempos de carga iniciales prolongados.

    Si su proyecto tiene contenido en el pie de página al que desea que llegue el usuario, el desplazamiento infinito puede resultar en una peor experiencia de usuario.

    También existen otras bibliotecas que proporcionan esta funcionalidad y que pueden ser las más adecuadas para las necesidades de su proyecto.

    Si deseas obtener más información sobre React, eche un vistazo a nuestra serie Cómo codificar en React.js o consulte nuestra página de temas de React para ver ejercicios y proyectos de programación.

    SUSCRÍBETE A NUESTRO BOLETÍN 
    No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

    Subir

    Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion