Meteor+React componentDidMount() issue


#1

I’m working on my first Meteor app, and I’m using both React and flow-router/react-layout for a multi-page application, as well as jquery-ui. This is my first JS-based app, so a good learning curve is involved for me.

On one of my pages, I have a query-ui accordion. In this component, I use componentDidMount to execute the jquery-ui required code, $("#accordion").accordion();. This then modifies the elements in the DOM, adding CSS classes.

When I navigate to this page from the home page, the accordion looks like it should. However, if I reload this page, then it does not; the CSS classes have not been added. The componentDidMount method does not trigger to modify the elements. I have to navigate back to the home page, then back, and it again looks correct, and have the expected CSS classes.

With my limited understanding, it seems that when I do a browser reload, the page is being rendered in a manor that prevents the componentDidMount method to trigger.

I’d appreciate any help anyone can provide. Thanks.


#2

Weird. componentDidMount should definitely be triggering. Can you share some code?


#3

It could be a race condition that only exists (for some reason) when the page is reloaded. Are you using any Meteor publications in this component? I’ve faced this a number of times, and I haven’t been able to come up with a good way to consistently handle it, tbh. Usually what happens is the component mounts, but Meteor pub/sub isn’t finished doing its thing until after the initial mount, which triggers a componentWillUpdate() as new info into this.data.whatever comes streaming in.

So, you might consider moving/copying the code into componentWillUpdate(), and slap a conditional in the render method based on the ready status of the publication. Nasty, I know… but if you want an even nastier solution, leave it where it is, but put it in a setTimeout … if it works inside a setTimeout, then you know almost without any doubt, that it is a race condition.

I wonder if there is any good way to delay the initial mounting in react until all the subscriptions are ready.

Edit: Slap a console.log in your componentDidMount() method and see if it fires when the page is reloaded. If it fires, then you know componentDidMount() is firing, and you’ll have a better idea of what the deal is.


#4

why you even render child component when it’s data are not loaded yet?
that is most common usecase and it should be avoided in parent render.

I am not react guy, just talking :smiley:


#5

That’s probably the best way to do it right now, duplicate the publication in the parent, and put a conditional around the entire child depending on if the subscription is ready.


#6

as usual, non-flux way so you need to decide if you want parent re-render more often or implement some condition in child
and meteor mixin does not make it much easier to tune if component should re-render :smiley:
good luck


#7

How in the parent do I know all of the children have rendered?


#8

I added the log. It does log it seems just before the refresh (when I saved the console.log code change in this instance). I do have a data object on the page, as it’s a form.

Oddly, setting a timeout does help, but, not completely. I am using this setTimeout(function(){$("#accordion").accordion()}, 3000); and even though three seconds is more than long enough, only one of the three divs’s in the according are getting decorated.


#9

To be clear, the jquery call is in the parent. In the parent, I render the children (in this case the mongo collection has three entries).


#10

Try wrapping the child components in a conditional such that they are only rendered when the subscriptions are ready


#11

Please forgive my ignorance but, I don’t understand how that would help. The children need to be completely rendered before the jQuery method is called. The componentDidMount SEEMS to be being called before the children do finish, and that is why their div’s aren’t getting decorated.

Also, I’m not adding a subscription manually, so is that happening ‘automagically’?

Thanks so much.


#12

Well, an issue that I have faced is jQuery plugins misbehaving when it expects a stable DOM, but new data comes in. So, the idea is that wrapping the child component in a conditional that says, don’t mount the child until the data is ready, could help prevent the problem from occurring. Just a possible solution! This is the part of React I don’t like =[


#13

That sounds reasonable. How would I create that conditional? Yes, I’m learning. :smile:


#14

something like this might work:

var subs = new SubsManager();

Parent = React.createClass({
  mixins: [MeteorReactData],
  getMeteorData(){
    subs.subscribe("myPublication");  // optionally using meteorhacks subscription manager
    return {
      subsReady: subs.Ready()
    }
  },
  componentDidMount(){
    //jQuery here or maybe in the child component
  },
  render() {
    return (
      <div>
        {this.data.subsReady ? 
        <Child /> : null }
      </div>
    );
  }
});