Infinite scrolling with React JS
Basically when scrolling you want to decide which elements are visible and then rerender to display only those elements, with a single spacer element on top and bottom to represent the offscreen elements.
Vjeux made a fiddle here which you can look at: jsfiddle.
Upon scrolling it executes
scrollState: function(scroll) { var visibleStart = Math.floor(scroll / this.state.recordHeight); var visibleEnd = Math.min(visibleStart + this.state.recordsPerBody, this.state.total - 1); var displayStart = Math.max(0, Math.floor(scroll / this.state.recordHeight) - this.state.recordsPerBody * 1.5); var displayEnd = Math.min(displayStart + 4 * this.state.recordsPerBody, this.state.total - 1); this.setState({ visibleStart: visibleStart, visibleEnd: visibleEnd, displayStart: displayStart, displayEnd: displayEnd, scroll: scroll });},
and then the render function will display only the rows in the range displayStart..displayEnd
.
You may also be interested in ReactJS: Modeling Bi-Directional Infinite Scrolling.
Check out our React Infinite Library:
https://github.com/seatgeek/react-infinite
Update December 2016
I've actually been using react-virtualized in a lot of my projects recently and find that it covers the majority of use cases a lot better. Both libraries are good, it depends on exactly what you're looking for. For instance, react-virtualized supports variable height JIT measuring via an HOC called CellMeasurer
, example here https://bvaughn.github.io/react-virtualized/#/components/CellMeasurer.
Update November 2018
A lot of the lessons from react-virtualized have been ported to the smaller, faster, more efficient react-window library from the same author.
import React, { Component } from 'react';import InfiniteScroll from 'react-infinite-scroller';const api = { baseUrl: '/joblist'};class Jobs extends Component { constructor(props) { super(props); this.state = { listData: [], hasMoreItems: true, nextHref: null }; } fetchData(){ var self = this; var url = api.baseUrl; if(this.state.nextHref) { url = this.state.nextHref; } fetch(url) .then( (response) => { return response.json() }) .then( (json) => { var list = self.state.listData; json.data.map(data => { list.push(data); }); if(json.next_page_url != null) { self.setState({ nextHref: resp.next_page_url, listData: list }); } else { self.setState({ hasMoreItems: false }); } }) .catch(error => console.log('err ' + error)); } } componentDidMount() { this.fetchData(); } render() { const loader = <div className="loader">Loading ...</div>; let JobItems; if(this.state.listData){ JobItems = this.state.listData.map(Job => { return ( <tr> <td>{Job.job_number}</td> <td>{Job.title}</td> <td>{Job.description}</td> <td>{Job.status}</td> </tr> ); }); } return ( <div className="Jobs"> <div className="container"> <h2>Jobs List</h2> <InfiniteScroll pageStart={0} loadMore={this.fetchData.bind(this)} hasMore={this.state.hasMoreItems} loader={loader}> <table className="table table-bordered"> <thead> <tr> <th>Job Number</th> <th>Title</th> <th>Description</th> <th>Status</th> </tr> </thead> <tbody> {JobItems} </tbody> </table> </InfiniteScroll> </div> </div> ); }}export default Jobs;