13

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.

3 Answers 3

8

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();
      }
    });
  }, {}
);
Sign up to request clarification or add additional context in comments.

Comments

4
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

Comments

3

I am the author of React Lazy Load Image Component, it should work fine with isomorphic applications.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.