I have a custom field that "shows up late" compared to the other fields in Meteor.user(). It's causing me problems handling data initialization. My question is, why does my custom field show up late? Here's the issue.
I have added a custom field to users like this:
if (Meteor.isServer) {
Meteor.publish('allusers', function() {
return Meteor.users.find({});
});
Meteor.publish('userData', function () {
if (this.userId) {
return Meteor.users.find({_id: this.userId},
{fields: {'lastViewedScenarios_id': 1 }});
} else {
this.ready();
}
});
}
And on the client, I get at the user data via createContainer, like this:
export default AppContainer = createContainer(() => {
Meteor.subscribe('userData');
return {
currentUser: Meteor.user(),
};
}, App);
But when I look at what happens when the page loads, I see this behavior:
on 1st call to componentWillReceiveProps:
currentuser:
_id : "DNFNaecyNWGMe4HrZ"
emails : Array[1]
roles : Array[1] /* SOMETIMES present, sometimes not! */
still loading the page, subsequent call to componentWillReceiveProps:
currentuser:
_id : "DNFNaecyNWGMe4HrZ"
emails : Array[1]
roles : Array[1]
lastViewedScenarios_id :MongoID.ObjectID /* Never present until 2nd call! */
What the? I am using alanning:roles, and maybe that's doing its own custom publish of userData. Whether that's a factor or not, my custom field lastViewedScenarios_id is only showing up after the initial population of currentuser, even though this data is all in the same Mongo collection.
My code needs to take action on initialization of the currentuser data, and this "initializes a bit at a time" behavior is making clean logic impossible here. Why is this happening, and can I do anything about it other than add lots of ugly initialization and testing for the presence of every field?
Thanks!
The safest way to ensure your data will be fully available when your component calls componentWillReceiveProps
is to only use your component when your userData
subscription is ready. This can be achieved by changing your AppContainer
:
export default AppContainer = createContainer(() => {
const subscriptionHandler = Meteor.subscribe('userData');
return {
loading: !subscriptionHandler.ready()
currentUser: Meteor.user(),
};
}, App);
Then in your App
component you can use the loading
prop to decide to use the component only when loading
is false.
Something like this (in your App's render()
method):
{
this.props.loading ?
<div>Loading...</div> :
<CleanLogicComponent user=this.props.currentUser />
}
Then, when CleanLogicComponent
's componentWillReceiveProps
gets called, all user data will be available.