Unable to retrieve MongoDB data from container when refreshing page with React


#1

Before page loads, my goal is to retrieve data from a MongoDB collection and inserting it into the page’s DOM. This works fine when user clicks through the app, but when refreshing the page, the Session variable doesn’t change state from false to true and it never renders in the DOM.

This is what my container looks like:

export default createContainer(function(){
  const subHandle = Meteor.subscribe("data");
  let routeCheck = FlowRouter.getParam("dataId");
  
subHandle.ready() ? Session.set("load", true) : Session.set("load", false);
  return{
  questions: MyChest.find({"itemData.itemId": routeCheck}).fetch()
  }
}, Main);

Now, in my componentDidMount() function, I first wait for the Session variable to return true (so that the DOM is rendered and ready to be manipulated) before applying the DOM changes:

  componentDidMount(){
    if(Session.get("load")){
      let text = this.props.questions[0].itemData.richText.openingMessage.text;
      document.getElementById("openingMessage").innerHTML = text;
    }
  };

So what happens is that when I refresh the page, the componentDidMount() is triggered as usual, but inside the if block, nothing is triggered. Turns out the Session variable never changes from false to true after the page refresh.

I’ve tried to change subscription to router level via FlowRouter, but I’m having reactivity issues and not sure where to go from here.


#2

Hello @sproleee,

Here there are two ways to resolve.

  1. Don’t Use session. Just add one more field to return statement like “loading” which will store value of current subscription handler state.

and in componentDidMount() first check subscriptionhandler is ready or not as shown below.

componentDidMount(){
if(!this.props.loading){
let text = this.props.questions[0].itemData.richText.openingMessage.text;
document.getElementById(“openingMessage”).innerHTML = text;
}
};

Thanks,
Tarun Sharma
Sr. Developer @ AIMDek Technologies Pvt Ltd
+91 9510657842


#3

Thanks for the reply.

I did have that same setup initially, but it didn’t work. That’s why I went the Session route.

When I refresh my page, subHandle.ready() is immediately false and the stuff in componentDidMount never gets called, even though my collection is present and already loaded.


#4

I should also say that when I wrap the code in componentDidMount() in a setTimeout function, it works with an obviously slight delay and unsightly UI with the lag period.

I just don’t understand why the component works perfectly fine when just browsing my app and waits for the subscription to load before rendering what’s beyond the if blocks, but when I refresh the page, it doesn’t wait until subscription is finished. I’m very confused as to why it’s happening.

The componentDIdMount doesn’t respond to state changes after refresh.


#5

Hello @sproleee,

You can use ReactMeteorData mixins in your app.

Please follow link for more information.
http://react-in-meteor.readthedocs.io/en/stable/meteor-data/
https://www.discovermeteor.com/blog/data-loading-react/

For Example.


var FlowDiary = React.createClass({
    mixins: [ReactMeteorData],
    getMeteorData: function() {
        var userId = Meteor.userId();
        var loading = false;

        if (Meteor.status().connected) {
            var subscriptionHandle = Meteor.subscribe("flowdiaries");
            loading = !subscriptionHandle.ready();
        }
        return {
            loading: loading,
            flowDiaries: FlowDiaries.find({
                userId: userId,
                bleedingDate: {
                    '$gte': this.state.start,
                    '$lte': this.state.end
                }
            }).fetch()
        };
    },
    render() {
if (this.data.loading) {
            return (
                <IonContent {...this.props}>
                  <AbsoluteMiddle>
                  <IonSpinner icon={icon} />
                  </AbsoluteMiddle>
                </IonContent>
            )
        }
if (!this.data.loading) {
      let text = this.props.questions[0].itemData.richText.openingMessage.text;
      document.getElementById("openingMessage").innerHTML = text;

// display Content
}
}

Thanks,
Tarun Sharma
Sr. Developer @ AIMDek Technologies Pvt Ltd
+91 9510657842


#6

For anyone who has the same problem as I had above, the way to fix this is to create a wrapper component that will subscribe to the DB data and send that data to the “main” component via props. That way, the component that needs the data will never have to directly wait for the subscription and all it will have to do is accept props. This results in no rendering errors whatsoever.