Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React lazy load/infinite scroll solutions

It took me a while to figure out how to lazy load images using the excellent React Lazyload component.

The demo lazy loaded images on scroll but when testing I could not get the same behavior.

The culprit was overflow: auto; which conflicted with the component working as intended.

What is the best way to lazy load large image gallery/slideshows in React?

React Lazyload (Really liking this component but want to investigate others)

React Virtualized (Seems heavy but feature-rich)

React Infinite (Higher barrier to entry due to complexity)

React Lazylist (Straight-forward but not sure if optimal for images)

Others...?

I have a universal/isomorphic application so some of the above will break due to window object unable to be used on the server.

like image 968
Vladimir Ramik Avatar asked Mar 16 '17 21:03

Vladimir Ramik


People also ask

Is infinite scroll lazy loading?

Infinite scroll uses lazy loading and executes its demand to load more data (products or content) at the bottom of the page, without requiring an action such as the click of a button. On-demand loading is used to optimize content delivery by reducing time consumption and memory usage.

Does React lazy increase performance?

The major benefit of lazy loading in React is performance. Loading less JavaScript code to the browser will reduce DOM load time and boost the performance of our application. Users are able to access a web page even if everything has not been loaded.

How do you lazy load in React?

import React from "react"; import { lazyLoader } from "./lazyLoader"; const Customer = lazyLoader(() => import("./Customer. js")); const Admin = lazyLoader(() => import("./Admin. js")); //Instead of regular import statements, we will use the above approach for lazy loading export default (props) => { if (props.


2 Answers

If you want a simpler lazy load solution and not have to use other people's packages/code, try using the IntersectionObserver API.

https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API

I wrote a Medium article on how to use it to lazy load images in a React component (implementation is essentially the same with vanilla JS).

https://medium.com/@parkjoon94/lazy-loading-images-intersectionobserver-8c5bff730920

You only really need this part of the code (snippet from above article):

this.observer = new IntersectionObserver(
  entries => {
    entries.forEach(entry => {
      const { isIntersecting } = entry;
      if (isIntersecting) {
        this.element.src = this.props.src;
        this.observer = this.observer.disconnect();
      }
    });
  }, {}
);
like image 111
jay p Avatar answered Oct 19 '22 19:10

jay p


import React from "react";
import PropTypes from "prop-types";
import axios from "axios";
import InfiniteScroll from "react-infinite-scroller";
const styles = theme => ({
  root: {
    textAlign: "center",
    paddingTop: theme.spacing.unit * 20
  }
});

class Parent extends React.Component {
  state = {
    allposts: [],
    posts: [],
    hasMore: true,
    curpage: 0,
    pagesize: 30,
    totalPage: 0,
    total: 0
  };

  componentDidMount() {
    axios.get("https://jsonplaceholder.typicode.com/posts").then(res => {
      let curpage = this.state.curpage;
      let posts = res.data.slice(
        curpage * this.state.pagesize,
        (curpage + 1) * this.state.pagesize
      );
      this.setState({
        allposts: res.data,
        posts: posts,
        total: res.data.length,
        totalPage: Math.ceil(res.data.length / this.state.pagesize)
      });
    });
  }

  loadmoreItem() {
    if (this.state.curpage + 1 < this.state.totalPage) {
      let curpage =
        this.state.curpage < this.state.totalPage
          ? this.state.curpage + 1
          : this.state.curpage;
      let posts = this.state.allposts.slice(
        0,
        (curpage + 1) * this.state.pagesize
      );
      this.setState({ posts: posts, curpage });
    } else {
      this.setState({ hasMore: false });
    }
  }

  render() {
    if (this.state.posts.length === 0) return <h1>loading...</h1>;
    else {
      console.log(this.state);
      return (
        <div>
          <Table
            hasMore={this.state.hasMore}
            posts={this.state.posts}
            loadmoreItem={this.loadmoreItem.bind(this)}
          />
        </div>
      );
    }
  }
}

export default Parent;

const Table = props => {
  console.log("props: ", props);
  return (
    <React.Fragment>
      <div style={{ height: "400px", overflow: "auto" }}>
        <InfiniteScroll
          pageStart={0}
          loadMore={props.loadmoreItem}
          hasMore={props.hasMore}
          loader={
            <div className="loader" key={0}>
              Loading ...
            </div>
          }
          useWindow={false}
          threshold={350}
        >
          <table>
            <tr>
              <th>id</th>
              <th>title</th>
              <th>body</th>
            </tr>
            {props.posts.map(item => {
              return (
                <tr>
                  <td>{item.id}</td>
                  <td>{item.title}</td>
                  <td>{item.body}</td>
                </tr>
              );
            })}
          </table>
        </InfiniteScroll>
      </div>
      <button onClick={props.loadmoreItem}>next</button>
    </React.Fragment>
  );
};

check live example here

https://codesandbox.io/s/x228lmm90q

like image 4
Raj Rj Avatar answered Oct 19 '22 18:10

Raj Rj