ParseReact icon indicating copy to clipboard operation
ParseReact copied to clipboard

InfiniteScroll

Open yamill opened this issue 10 years ago • 8 comments

How would one go about doing an infinite scroll?

I ask because in my render() function I can't setState.

yamill avatar Jul 01 '15 15:07 yamill

perhaps you could use something like #83 where you have a query that gets your data at some index limited to some number of items (the size of the scrolling window) and when you get new data, you append it to a list you keep in state.

  new Parse.Query('ScrollingStuff'))
   .containedIn('index', [position, pos + 1, pos + 2])
   .limit(3),

bytesandwich avatar Jul 02 '15 00:07 bytesandwich

@jackphel hmmm is there a simpler way of doing this? for example concat each query?

though, i wouldn't know where to put it since we don't have a proper callback when the query finishes loading.

yamill avatar Jul 02 '15 14:07 yamill

I'd like a componentWillUpdate for this.data, but maybe you could have the query's history saved in this.state, and get the current window (which will necessarily not be in this.state because you don't know when it's been updated) from this.data . When you dispatch the mutation that moves your query's index, you can first save the last query value into your component's state. If you're reloading previously loaded indexes, this would call for a little bit more work to update your query history into this.state.

I'm wondering whether for the library it makes sense to have a lifecycle method for component will update data, and maybe allow this method to take the new data and reconcile it with the old, so you could just concat the new query results onto the old in your situation. @andrewimm Would you mind a pull request for this like #83 ?

bytesandwich avatar Jul 02 '15 20:07 bytesandwich

@jackphel I figured you can just create another query that picks up new data...I know this isn't the cleanest but it works. I'll probably create an example for this.

yamill avatar Jul 17 '15 18:07 yamill

@yamill you're able to append to the data you have with a query?

bytesandwich avatar Jul 17 '15 20:07 bytesandwich

@jackphel oh no nevermind I thought I could do it by creating an identical query but that means it will call the query twice.

it's better to just have a solution with a callback or something.

yamill avatar Jul 20 '15 14:07 yamill

Honestly, @yamill while parse-react is awesome for what it does, I think you're probably better of using flux for InfiniteScroll since this isn't easy in parse-react.

bytesandwich avatar Jul 22 '15 20:07 bytesandwich

I ended up using an great npm module called react-infinite It does the trick without too much dancing around. Here is a basic component. I just ripped out all irrelevant things so best to check the docs on react-infinite.

var React = require('react');
var Parse = require('parse').Parse;
var ParseReact = require('parse-react');
var LoadInfinite = require('../../components/layout/load-infinite.jsx');
// This is a basic component that renders each list item.
// It return the item when the object is clicked
var Item = require('../../components/list/item-admin-discipline.jsx');
// NPM react-infinite
// Not my work so cudos to the author/s
var List = require('react-infinite');

var dataPageSize = 20;
var recordSkip = 0;
var dataSourceLoad = [];

var MyListComponent = React.createClass({

  getInitialState: function() {
    return {
      isLoadingData: true,
      dataSource: []
    };
  },

  observe: function() {
    var subSetResultsQuery = new Parse.Query('YourParseClass');
    subSetResultsQuery.skip(recordSkip);
    subSetResultsQuery.limit(dataPageSize);

    return {
      user: ParseReact.currentUser,
      subSetResults: subSetResultsQuery
    };
  },

  componentWillUpdate: function() {
    if (this.pendingQueries().length < 1 && this.state.isLoadingData) {
      dataSourceLoad = [];
      var self = this;
      this.data.subSetResults.forEach(function (entry) {
        var objectToRenderInListComp = {
          objectId: entry.objectId,
          name: entry.name
        }
        dataSourceLoad.push(<Item onClickItem={self.onSelectionChange} key={entry.objectId} objectToRenderInListComp={objectToRenderInListComp} />);
      });
      this.setState({
        isLoadingData: false,
        dataSource: this.state.dataSource.concat(dataSourceLoad)
      });
    }
  },

  onSelectionChange: function(data) {
    //Do something with the returned object that is now stored on data
  },

  handleInfiniteLoad: function() {
    this.setState({ isLoadingData: true });
    recordSkip = this.state.dataSource.length;
    this.refreshQueries(['subSetResults']);
  },

  loadIndicator: function() {
    return (
      <LoadInfinite />
    )
  },

  render: function() {
    return (
      <List
        elementHeight={55}
        containerHeight={someCalculatedHeight}
        infiniteLoadBeginBottomOffset={200}
        onInfiniteLoad={this.handleInfiniteLoad}
        loadingSpinnerDelegate={this.loadIndicator()}
        isInfiniteLoading={this.state.isLoadingData}
      >
        {this.state.dataSource}
      </List>
    );
  }
});

module.exports = MyListComponent;

WilfredGreyling avatar Nov 02 '15 19:11 WilfredGreyling