Browser Efficient Infinite List For React

Category: Scroll | December 4, 2017
Author: SourceDecoded
Views Total: 473
Official Page: Go to website
Last Update: December 4, 2017
License: MIT

A browser efficient infinite list for React apps that allows loading of items with differing heights and sizes.

The minimal API is to create a ListViewDataSource from clarity-react-infinite-list, populate it with an array of data, and add a ListViewcomponent with that data source and a renderRow callback which takes an item from the data source and returns a renderable component.

More features:

  • Lazy load and fetch data from API requests in batches.
  • Infinite number of items and batches
  • Items can have dynamic heights and sizes, that do not have to be declared before hand.
  • Add in a custom loading component.

Installation:

# Yarn
$ yarn add clarity-react-infinite-list

# NPM
$ npm install clarity-react-infinite-list --save

Usage:

Import the library.

import React, { Component } from "react";
import { connect } from "react-redux";
import { getUsersBatch, setFetchingUsersStatus } from "../../actions";
import { ListView, ListViewDataSource } from "clarity-react-infinite-list";
import ListItem from "../layouts/ListItem";

The basic example.

const styles = {
    container: {
        position: "absolute",
        top: 0,
        left: 0,
        width: "100%",
        height: "100%"
    },
    header: {
        boxShadow: "0 1px 8px rgba(0,0,0,.3)",
        fontSize: "18px",
        textAlign: "center",
        height: "80px",
        lineHeight: "80px",
        color: "#f2f2f2",
        backgroundColor: "#1e88e5",
        position: "relative",
        zIndex: "2",
        whiteSpace: "nowrap",
        overflow: "hidden",
        textOverflow: "ellipsis"
    },
    listView: {
        paddingTop: "16px",
        position: "absolute",
        top: "80px",
        bottom: "0",
        left: "0",
        right: "0",
        overflowY: "scroll",
        WebkitOverflowScrolling: "touch"
    },
    loading: {
        textAlign: "center",
        paddingBottom: "16px"
    }
};

class Main extends Component {
    constructor(props) {
        super(props);

        this.state = {
            dataSource: new ListViewDataSource(30),
            lastUserId: 0
        };

        this._renderRow = this._renderRow.bind(this);
        this._onEndReached = this._onEndReached.bind(this);
        this._loadingComponent = this._loadingComponent.bind(this);
    }

    _renderRow(rowData, rowId) {
        return (
            <ListItem key={rowId} rowData={rowData} rowId={rowId} />
        );
    }

    _onEndReached() {
        if (!this.props.isFetchingUsers) {
            this.props.setFetchingUsersStatus(true);
            this.props.getUsersBatch(this.state.lastUserId);
        }
    }

    _loadingComponent() {
        return (
            <div style={styles.loading}>Loading...</div>
        );
    }

    componentWillMount() {
        this.props.setFetchingUsersStatus(true);
        this.props.getUsersBatch(this.state.lastUserId);
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.users[nextProps.users.length - 1] && this.state.lastUserId !== nextProps.users[nextProps.users.length - 1].id) {
            this.setState({
                dataSource: this.state.dataSource.cloneWithRows(nextProps.users),
                lastUserId: nextProps.users[nextProps.users.length - 1].id,
            });
        }
    }

    render() {
        return (
            <div style={styles.container}>
                <div style={styles.header}>
                    Clarity React Infinite Scroll Example
                </div>
                <ListView style={styles.listView}
                    dataSource={this.state.dataSource}
                    renderRow={this._renderRow}
                    onEndReached={this._onEndReached}
                    loadingComponent={this._loadingComponent}
                    onEndReachedThreshold={5000}
                    ref={listView => this.listView = listView} />
            </div>
        );
    }
}


const mapStateToProps = (state) => {
    return {
        users: state.users,
        isFetchingUsers: state.isFetchingUsers
    };
};

const mapDispatchToProps = {
    getUsersBatch,
    setFetchingUsersStatus
};

export default connect(mapStateToProps, mapDispatchToProps)(Main);

Preview:

Browser Efficient Infinite List For React