In general, in Meteor, we’ve gotta be careful info we want to be reactive. If we use Meteor.user() in a computation, then that will be reactive when absolutely any info inside the user object changes, which can be lots if the user object has lots of changing info.
I read somewhere (can’t find it at the moment) that if you want to react to a specific property of a document, you can do just that with the fields option, which will cause reactive updates less often and perform better:
Meteor.users.findOne(id, {fields: {"profile.foo": 1}}) // react only to changes on profile.foo
Additionally, we can throttle reactivity and limit it to, say, at most one update per 2-second time window:
let profileFoo = new ReactiveVar('') // initial value of empty string
let setProfileFoo = _.throttle(value => profileFoo.set(value), 2000)
// ^ fire this logic at most once in any
// given 2-second period of time.
// See http://underscorejs.org/#throttle
Tracker.autorun(computation => {
let foo = Meteor.users.findOne(id, {fields: {"profile.foo": 1}})
setProfileFoo(foo)
})
class Foo extends React.Component {
render() {
// this render method will only fire at most once per 2 seconds.
}
getMeteorData() {
// will only change at most once in any 2-second time window, and only on the profile.foo property!
let foo = profileFoo.get()
return {foo}
}
}
We use TrackerReact instead of MeteorGetData and, in case anybody tried, would be interested to know if there is any difference. We actually use it in production and render about 1000 items in virtual lists :?
Sorry for the absence. UK bed time called but Im awake now. I’ll go through the replies and see what works best. Thanks for all replies!
Edit:
I think I have not sent the message correctly. Why your solution will not work? I’m not rendering anything so I can not render something else while I wait on their data to be loaded in client. Maybe what I want can be done another way? I’m still learning Redux but for now I’ll try with pure React and Meteor.
I want to bind a user profile field. So far what I did only works in Chrome but getMeteorData() is slow in other browsers. The scenario is, when a user is on their profile page, all fields will be blank. Now they will fill in the blanks then hit update. Now…those fields have the value of what was entered and they can update at will.
even with fast-render, do not expect user collection to be available all the time.
So test if this.data.user is available inside render(), if not return placeholder dom element.
If it is available you can return your form.
Nothing is needed in componentDidMount(), that getMeteorData will take care of re-renders during all changes of user record.
when you have your subscription in some higher component, than use that component to render form only when it is already ready and pass there props whatever you want and do not render that form component before user data are ready.
that way you can initiate your form state based on passed properties from parent component.
Fast-Render makes the userId immediately available. You should use that for auth checks, separate from the user collection. And if you’d want, you could check the user collection and block re-rendering in a componentShouldUpdate until it becomes available, i.e. combined with SSR.
@sylar maybe you want to check out TrackerReact. Here is a basic example, my only one public, that shows how you could deal with user and user authentication:
@sergiotapia we have not found any drawbacks. And since the package is literally just a few lines, we decided to bring it into production. On the repo was a issue discussion about that.
One of the benefits is that it brings meteors known plug & play, without freezing states, to react in meteor.
@sashko Your method did worked; with more code but a user could not clear the field. This made me invested more about Meteor and I’ve found Meteor.autorun.
I had to change my original code from:
To:
Meteor.publish("userData", function () {
...
I needed to add the subscription to FlowRouter:
FlowRouter.route('/profile', {
name: 'profile',
action(){
var subs = Meteor.subscribe('userData');
Meteor.autorun(function() {
if (subs.ready()) {
ReactLayout.render(App, {
nav: <Nav />,
content: <Profile user={ Meteor.user() }/> // passing the props to getInitialState()
});
}
});
}
});
Now my getInitialState() looks like this:
...
fname: this.props.user.profile.firstName,
...
formSubmit() {
let fname = this.state.fname;
let students = {
firstName: fname,
...
};
Meteor.users.update( { _id: Meteor.userId() }, {
$set: {profile: students}
});
},