Pagination using React, ES6, and ReactiveVar (Meteor Guide)

This is regarding infinite scroll. I’ve read through several other resources and thought I was in the clear when I found this great screencast, but I’m still struggling to make this work.

The pagination itself functions great, but I’m getting a jump up to the top of the screen when load more items. After reading @sacha’s Discover Meteor article on the topic and a couple GitHub issues that @tmeasday chimed in on, it seems like the problem has something to do with updating my rective var when the subscription isn’t ready, but my attempts at solving that haven’t worked.

If anybody has solved this for themselves in a React/ES6 context (following the Meteor Guide), I’d love to hear about it.

Here’s my publication:

import { SimpleSchema } from 'meteor/aldeed:simple-schema';
import { Meteor } from 'meteor/meteor';
import { Items } from '../items.js';

Meteor.publish('items.feed', (limit) => {
  new SimpleSchema({
    limit: { type: Number },
  }).validate({ limit });

  return Items.find({}, { sort: { createdAt: -1 }, limit: Math.min(limit, MAX_RESOURCES) });
});

Here’s my container:

import { Meteor } from 'meteor/meteor';
import { createContainer } from 'meteor/react-meteor-data';
import { ReactiveVar } from 'meteor/reactive-var';
import IndexPage from '../pages/IndexPage.jsx';
import { Items } from '../../../api/items/items.js';

const ITEMS_PER_PAGE = 3;
const pageNumber = new ReactiveVar(1);

export default createContainer(() => {
  const itemsHandle = Meteor.subscribe('items.feed', ITEMS_PER_PAGE * pageNumber.get());
  const loading = !itemsHandle.ready();

  const loadMore = () => {
    pageNumber.set(pageNumber.get() + ITEMS_PER_PAGE);
  };

  return {
    items: !loading ? Items.find({}, { sort: { createdAt: -1 } }).fetch() : [],
    loadMore,
    loading,
  };
}, IndexPage);

Somebody, anybody :slight_smile:

+1 I’m having the same issue.

one thing you can do is pass the value into your URL params =)

How bout using the method in the OP?

So, I was having the same problem and watching the screencast posted by OP I found the solution.

The main difference between OP’s example and the screencast is that OP uses createContainer and the screencast uses Komposer. It turns out that while Komposer can re-render the comonent only when the subscription handle is ready, createContainer always calls render. So the problem is, that when the handle is updated, it stops being ready, so the component render is called without data, and that makes the screen scroll up and the data to be pulled off from the dom.

The solution: Checking the meteor guide for createContainer, there a section on preventing re-renders:

Turns out the solution is passing the handle state as a prop, and avoid rendering the component in react unless the data is ready, using shouldComponentUpdate(nextProps, nextState). Note that shouldComponentUpdate is not checked for the first render or when forceUpdate is called.

So, the solution for OP should be something like this added to the IndexPage component:

    shouldComponentUpdate(nextProps, nextState) {
        const { items} = nextProps;
        return items.length > 0;
    }

I hope this helps somebody. I think that the fact that the component will re-render with a non-ready handle when the handle is updated could be better clarified in the documentation.

1 Like

Hi @jaymot, we are implementing the pagination feature and have the same code as you do. However, we met a problem which makes the old subscription not unsubscribed when it is called again ( I use reactive var too ). So the data keeps being added but none was removed. Have you ever met the same issue ?