10

I've tried to get a minimal example of infinite scroll. So I have this:

var React = require('react-native');

var {
    StyleSheet,
    View,
    Image,
    ListView,
    } = React;

var data = [
    {
        "id": 1,
        "profile_picture": {
            "href": "//like1.r.worldssl.net/ui_big/1305634.jpg"
        }
    },
    {
        "id": 2,
        "profile_picture": {
            "href": "//like1.r.worldssl.net/ui_big/1305634.jpg"
        }
    },
    {
        "id": 3,
        "profile_picture": {
            "href": "//like1.r.worldssl.net/ui_big/1305634.jpg"
        }
    },
    {
        "id": 4,
        "profile_picture": {
            "href": "//like1.r.worldssl.net/ui_big/1305634.jpg"
        }
    },
    {
        "id": 5,
        "profile_picture": {
            "href": "//like1.r.worldssl.net/ui_big/1305634.jpg"
        }
    },
    {
        "id": 6,
        "profile_picture": {
            "href": "//like1.r.worldssl.net/ui_big/1305634.jpg"
        }
    }

];

var InfiniteScreen = React.createClass({
    getInitialState: function () {
        return {
            isLoadingTail: false,
            dataSource: new ListView.DataSource({
                rowHasChanged: (row1, row2) => row1 !== row2,
            })
        };
    },
    componentDidMount: function () {
        this.setState({
            dataSource: this.getDataSource(data)
        });
    },
    renderRow: function (item) {
        return (
            <View>
                <Image style={{width: 80, height: 80}} source={{uri: 'http:' + item.profile_picture.href}}/>
            </View>
        );
    },
    onEndReached: function () {
        console.log('onEndReached', this.state.isLoadingTail);
        if (this.state.isLoadingTail) {
            // We're already fetching
            return;
        }
        this.setState({
            isLoadingTail: true
        });

        this.setState({
            isLoadingTail: false,
            dataSource: this.getDataSource(data)
        });
    },
    getDataSource: function (users):ListView.DataSource {
        return this.state.dataSource.cloneWithRows(users);
    },
    render: function () {
        return (
            <View>
                <ListView
                    dataSource={this.state.dataSource}
                    renderRow={this.renderRow}
                    onEndReached={this.onEndReached}
                />
            </View>);
    }
});

If I scroll to the very bottom, onEndReached() is fired, but the new data doesn't appear. Any ideas?

Ladislav M
  • 2,157
  • 4
  • 36
  • 52

4 Answers4

27

You always clone your data source with the same data, so nothing new appears. Here is a working example (add new data via concat):

var React = require('react-native');

var {
    StyleSheet,
    View,
    Image,
    ListView,
    } = React;

var data = [
    {
        "id": 1,
        "profile_picture": {
            "href": "//like1.r.worldssl.net/ui_big/1305634.jpg"
        }
    },
    {
        "id": 2,
        "profile_picture": {
            "href": "//like1.r.worldssl.net/ui_big/1305634.jpg"
        }
    },
    {
        "id": 3,
        "profile_picture": {
            "href": "//like1.r.worldssl.net/ui_big/1305634.jpg"
        }
    },
    {
        "id": 4,
        "profile_picture": {
            "href": "//like1.r.worldssl.net/ui_big/1305634.jpg"
        }
    },
    {
        "id": 5,
        "profile_picture": {
            "href": "//like1.r.worldssl.net/ui_big/1305634.jpg"
        }
    },
    {
        "id": 6,
        "profile_picture": {
            "href": "//like1.r.worldssl.net/ui_big/1305634.jpg"
        }
    }

];

var InfiniteScreen = React.createClass({
    getInitialState: function () {
        return {
            isLoadingTail: false,
            dataSource: new ListView.DataSource({
                rowHasChanged: (row1, row2) => row1 !== row2,
            })
        };
    },
    componentDidMount: function () {
        this._data = [];
        this.setState({
            dataSource: this.getDataSource(data)
        });
    },
    renderRow: function (item) {
        return (
            <View>
                <Image style={{width: 80, height: 80}} source={{uri: 'http:' + item.profile_picture.href}}/>
            </View>
        );
    },
    onEndReached: function () {
        console.log('onEndReached', this.state.isLoadingTail);
        if (this.state.isLoadingTail) {
            // We're already fetching
            return;
        }
        this.setState({
            isLoadingTail: true
        });

        this.setState({
            isLoadingTail: false,
            dataSource: this.getDataSource(data)
        });
    },
    getDataSource: function (users):ListView.DataSource {
        this._data = this._data.concat(users);
        return this.state.dataSource.cloneWithRows(this._data);
    },
    render: function () {
        return (
            <View style={styles.container}>
                <ListView
                    dataSource={this.state.dataSource}
                    renderRow={this.renderRow}
                    onEndReached={this.onEndReached}
                />
            </View>);
    }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    backgroundColor: '#F5FCFF',
  },
});
vkurchatkin
  • 13,364
  • 2
  • 47
  • 55
0

https://facebook.github.io/react/docs/component-api.html#setstate

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value. There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.

so the problems is here

    this.setState({
        isLoadingTail: true
    });

    this.setState({
        isLoadingTail: false,
        dataSource: this.getDataSource(data)
    });
0

I've been looking for this solution for very long time. Finally I came up with this light weight library :-

https://www.npmjs.com/package/rn-infinite-scroll

import InfiniteListView from 'rn-infinite-scroll';

<InfiniteListView
    data ={this.state.items}
    renderRow={this.renderRow}
    canLoad={this.canLoad()}
    isLoading={this.state.isLoading}
    onLoad={this.onLoad}
/>
0

ListView is currently Deprecated. You will have to use FlatList or SectionList. You can find an example of infinite scroll using FlatList in this answer for another question. https://stackoverflow.com/a/47710224/7477198.

Haseeb A
  • 5,356
  • 1
  • 30
  • 34