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.
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.
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.
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
good luck
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.
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’?
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 =[