Multiple Meteor.subscribe() and too many re-renders of component(s)

Hi guys!

So I have a Meteor 1.4.x app using react, react-router and MDGs react-meteor-data package. In general everything is working great, but some components seem to (re-) render way too often.

Let’s say I have a simple component like so:

class ItemList extends React.Component {
    render {
        if (this.props.loading) {
            return <Loading />
        } else {
            console.log('ItemList READY!');
            return (...)
        }
    }
}

const ItemListContainer = createContainer((props) => {
    const sub1 = Meteor.subscribe('getItems', props.supplierId);
    const sub2 = Meteor.subscribe('foobar');
    let loading = !sub1.ready() || !sub2.ready();
    return {
        loading,
        otherStuff ...
    }
}

So the thing is … for whatever reason, even on initial page-load, the 'ItemList READY!' console.log shows up 4 times in my console! By console logging I can also see, that the single items inside this ItemList component are rendered 4 times over.

I do not understand what I am doing wrong … I thought that my loading prop should show my <Loading/> spinner until all subscriptions are ready and then my actual component is rendered once.

I hope you guys can help! :slight_smile:
Thanks a bunch in advance,

best, P

1 Like

Any input on this guys? :slight_smile: This should be a pretty common usecase I think …

EDIT:
This sh*t is getting worse! I am now at 9 re-renders on intital load in another view … wtf? I do not understand what is going on …

To lower the number re-render, you should use React.PureComponent as only it only recalculates its entry in the virtual DOM if the props have mutated.

I will try that @pierreeric thanks a bunch for your input! :slight_smile:
just fyi at all: I found the initial reason for my problem (that I didn’t mention in my OP): apparently englue/meteor-publish-composite seems to handle the whole subscription readiness wrong. As soon as I rewrote my publication to a standard Meteor.publish and returned an array of mongo cursors, sub.ready() worked as expected and now I am down to a rocksteady one to sometimes two (re-)renders.

1 Like

OK new problem … could not stick to the standard Meteor.publish as the two collection cursors that are returned by this publication are dependent on each other!
So I went back to publishComposite but I am stuck with my old problem again - but worse this time.
It sometimes completely breaks my code as I do not know when the subscription is ready.
Any ideas on this?

4x is okay. You use Meteors container which executes the function within the container everytime a reactive source changes. This is how Tracker works.

const ItemListContainer = createContainer((props) => {
const sub1 = Meteor.subscribe('getItems', props.supplierId);
const sub2 = Meteor.subscribe('foobar');
let loading = !sub1.ready() || !sub2.ready();
return {
    loading,
    otherStuff ...
}

}

If sub1 is ready, the function executes and the same behavior happens if sub2 is ready. So Meteors container passes new props to the React component which will automatically do a render. You can control React’s rerendering with shouldComponentUpdate. You can read more about the lifecycle methods here.

Just check if your data is ready, f.e:

    const ItemListContainer = createContainer((props) => {
     const sub1 = Meteor.subscribe('getItems', props.supplierId);
     const postings = Postings.find().fetch();
     const loading = !sub1.ready()
     return {
             postings
    }
 }

And within your React component you check can do something like this:

render() {
    if(this.props.loading) {
     return <div>Loading...</code>;
   } else {
      if(this.props.postings) {
         return [....]
      } else {
         return <div>No posts available</div>;
     }
   }
}

The call of the render method doesn’t mean that your DOM will be updated. It only means that React calculates against its VDOM and checks if the DOM needs an update.

I am using your suggested render() logic already! :slight_smile:
I just thought there might be a better solution to basically prevent all these rerenders but I will just leave it as is for now!
Thanks for your reply!