Meteor React renders twice after subscription are ready

966 Views Asked by At

I'm using Meteor with react and FlowRouter to handle subscriptions. I find that when my component renders it will render twice after a few seconds, but only when I have the meteor mixin subscribed to a subscription.

For example:

logged this.data

PeoplePage = React.createClass({
    displayName:"People",
    mixins: [ReactMeteorData],
    getMeteorData() {
        const subHandles = [
            Meteor.subscribe("allPeople"),
        ];

        const subsReady = _.all(subHandles, function (handle) {
            return handle.ready();
        });

        return {
            subsReady: subsReady,
            people: People.find({}).fetch(),
        };
    },
    render(){
        if(this.data.subsReady == false){
            return (<Loading/>);
        } else {
            console.log(this.data);

            ........

        }

The same information is shown twice. Is this due to fast render that FlowRouter uses, or is it something that I am doing incorrectly?

2

There are 2 best solutions below

1
On

Hmm, I guess the problem is that you are triggering the subscription every time, when the component re-renders.. I haven't tried it, but you could check if this will solve the problem

getMeteorData() {
    const subsReady = _.all(this.subs || [{}], function (handle) {
        if (typeof handle.ready == 'function') 
            return handle.ready();

        return false;
    });

    if (!subsReady) // you can extend it, to provide params to subscriptions
        this.subs = [
           Meteor.subscribe("allPeople")
        ];

    return {
        subsReady: subsReady,
        people: People.find({}).fetch(),
    }
}

It should not trigger the subs if they are already ready.

Be aware, that mustn't pass an empty array to _.all, because of this:

_.all([], function(a) {return a.b()}) // true

this is why I added an empty object to the array, so this way you can check for the ready member..

1
On

I would suggest doing to subscription within the componentWillMount() function. This way, you make sure that you only subscribe once before the initial render().

getMeteorData() {
    var ready = _.all(this.subHandles, function (handle) {
        return handle.ready();
    });

    return {
        subsReady: ready,
        people: People.find({}).fetch()
    }            
},
componentWillMount() {
    this.subHandles = [];
    this.subHandles.push(Meteor.subscribe('allPeople');
},
componentWillUnmount() {
    this.subHandles.map(function(handle) {
        handle.stop();
    });
}

If it still renders twice, I would suggest trying to turn of fast render for the route and check if this problem still occurs.