44

Building a React Infinite Scroller Component from Scratch

 5 years ago
source link: https://www.tuicool.com/articles/hit/zMBbuqV
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Building a React Infinite Scroller Component from Scratch

3UfIjqZ.png!web

We all know the great content discovery experience where we can just scroll and scroll, discovering more items, people and photos. When building our web or mobile apps, we often want to give this great experience to our users.

In this tutorial, we are going to build a react infinite scroll with pure JavaScript and embed it into a ReactJS component.

With that component, we can achieve some awesome things:

  1. Fetching data from an API in JSON format
  2. Inject data into DOM element
  3. Use addEventListener to bind to the scroll event, and handle Paging using a common API
  4. Use internal state to store and append data
  5. Calculate the bottom of an expanding container

So, let’s dive in- step by step.

  • Tip: Use tools like Bit to turn your components into reusable Lego bricks. Create a collection, share your components, use them anywhere and build faster with your team. Give it a try.

Let’s get started

Use code sandbox to kick-start the project with create-react-app .

uU7Fziq.png!web

You’ll see the editor and the output browser.

mMVbeqA.png!web

Create a component structure used is the one below.

7FbUbeI.png!web

Fetching data from API and using it in the scrolling component

Import the necessary library.

import React from 'react'
import fetch from 'isomorphic-fetch'

Use isomorphic-fetch to fetch the data easily.

Create a class Infinitescroll

class Infinitescroll extends React.Component {
   render() {
     return <div />;
   }
 }
export default Infinitescroll;

Include it in Index.js

import React from "react";
import ReactDOM from "react-dom";
import Infinitescroll from "./components/infinitescroll";
import "./styles.css";

Also, in the index.js .

function App() {
  return (
     <div className="container">
       <h1>User</h1>
       <Infinitescroll />
     </div>
   );
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

The result should be:

iuQbu2U.png!web

Now, create a state variable to store data from API:

state = {
  data: [],
  per: 3,
  page: 1,
  total_pages: null,
};

Use a function to fetch data from an API

loadUser = () => {
   const { per, page, data } = this.state;
   const url = `https://reqres.in/api/users?   per_page=${per}&page=${page}`;
      fetch(url)
     .then(response => response.json())
     .then(json =>
      this.setState({
           data: son.data,
           scrolling: false,
           total_pages: json.total_pages
     })
  );
};

And render it:

render() {
     return (
       <ul>
       {this.state.data.map(data => (
          <li key={data.id}>
            <div>
               <div>
                  <img src={data.avatar} />
               </div>
               <div>{data.first_name}</div>
               <div>{data.last_name}</div>
            </div>
          </li>
       ))}
      </ul>
  );
}

Rendering the component when the page loads- this can be achieved using componentWillMount .

componentWillMount() {
   this.loadUser();
}

And the result:

3EvIzuJ.png!web

Loading More Data

So, before loading the next page on-scroll, we need to load more data.

Add a new state variable called prevState to get next page value and call loadUser .

loadMore = () => {
    this.setState(
      prevState => ({
        page: prevState.page + 1,
        scrolling: true
      }),
      this.loadUser
    );
  };

Call this function on clicking Load More button.

<div>
        <ul>
          {this.state.data.map(data => (
            <li key={data.id}>
              <div>
                <div>
                  <img src={data.avatar} />
                </div>
                <div>{data.first_name}</div>
                <div>{data.last_name}</div>
              </div>
            </li>
          ))}
        </ul>
        <button
          onClick={e => {
            this.loadMore();
          }}
        >
          Load More
        </button>
      </div>

The result…

bqInUre.gif

So, this is pretty awesome but we have a problem: the old data gets replaced by the new one.

To solve this, append the new response to the old data.

fetch(url)
      .then(response => response.json())
      .then(json =>
        this.setState({
          data: [...data, ...json.data],
          scrolling: false,
          total_pages: json.total_pages
        })
     );

The result…

MNZjQbM.gif

Well, it works just fine!

Trigger loadMore with scroll event

For the final part, trigger loadMore on a scroll event.

First, get last <li> with getQuerySelector. Calculate the element offset to get current page offset. If page offset is greater than the Offset of last item that means scrollbar is near the last offset. This should trigger loadMore .

handleScroll = () => { 
  var lastLi = document.querySelector("ul.container > li:last-child");
  var lastLiOffset = lastLi.offsetTop + lastLi.clientHeight;
  var pageOffset = window.pageYOffset + window.innerHeight;
if (pageOffset > lastLiOffset) {
       this.loadMore();
  }
};

Bind scroll listeners to the scroll handler.

componentWillMount() {
    this.loadUser();
    this.scrollListener = window.addEventListener("scroll", e => {
      this.handleScroll(e);
    });
  }

The result:

faA3qmn.gif

Great! That’s it. Your component is now ready! You can now use Bit to share it with your team, add it to your component collection and use it anywhere.

Quick Recap

In this post we learned how to implement a React infinite scroll component.

First, we learned how to fetch data from an API, and render it. With loadMore and handleScroll , we calculated the position of the scrollbar. Whenever the scrollbar is near the bottom of the window, fetch more data and append it to the existing data and render the component.

Hope you liked this post, and please feel free to comment and ask any questions! You can also leave me a few :clap: if you liked it. Cheers!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK