methodx
December 10, 2016, 6:51am
1
I’m relatively new to Meteor and one of the most frustrating things I’ve encountered so far is when I’m trying to load some initial data, I always get undefined. For example, users can make posts and then they can edit them. When they click an edit button, they’re taken to a separate edit page, but when I try to load the initial collection data it always comes back undefined.
componentDidMount () {
this.setState({
test: this.getTestData()
})
}
getTestData () {
const temp = TestCollection.findOne({name: 'test_post_1'})
return temp.post
}
When componentDidMount fires off, TestCollection hasn’t finished loading. So how do I do this? Normally I would just do something like…
const testing = this.getTestData()
if (typeof testing === 'undefined') {
return 'Loading...'
} else {
return testing
}
I can’t do that if the user is loading in existing data that needs to be edited.
Here’s an example repo I created.
1 Like
Try wrapping your code in a Tracker.autorun function, sounds like your data is loading before the rest of your application is finished running.
methodx
December 10, 2016, 7:39am
3
Put it inside componentDidMount
?
Tracker.autorun(function () {
// your code
});
methodx
December 10, 2016, 7:58am
5
componentDidMount () {
Tracker.autorun(() => {
this.setState({
test: this.getTestData()
})
})
}
Just results in Uncaught TypeError: Cannot read property 'post' of undefined(…)
Hmm… does it return undefined if you start at the root of the object?
methodx
December 10, 2016, 8:07am
7
I’m not sure what you mean by “root of the object”. This is the exact code I’m using for the example.
“temp” in this case would be your object being returned from the server. I’d check start there to move backwards and see if it returns anything.
methodx
December 10, 2016, 8:26am
9
This seems to have done the trick:
componentDidMount () {
Tracker.autorun(() => {
const test = this.getTestData()
if (typeof test !== 'undefined') {
this.setState({
test: this.getTestData().post
})
}
})
}
Thank you for the help!
1 Like
sbr464
December 10, 2016, 9:40am
10
If you don’t need the autorun after you have valid data, you can pass a param and call stop()
Tracker.autorun((c) => {
//after the setState,
c.stop()
})
1 Like
Isn’t this the exact reason for things like createContainer, and TrackerReact?
import React, { Component } from 'react';
import {createContainer} from 'meteor/react-meteor-data';
class MyComponent extends Component {
constructor(props) {
super(props);
}
render() {
return <p>{testData.name}</p>;
}
}
export default MyComponentContainer = createContainer(() => {
return {
testData: TestCollection.findOne({name: 'test_post_1'})
}
}, MyComponent);
3 Likes
ffxsam
December 10, 2016, 10:54pm
12
I second what @copleykj said. Try to avoid putting Meteor-specific stuff in your React components (keep them pure React). Use createContainer
to handle Meteor stuff (Mongo collections, Tracker, etc) and pass results into your React component via the return
statement.
methodx
December 10, 2016, 11:34pm
13
I was using TrackerReact. It didn’t do anything for my specific use case.
Really? The very purpose of TrackerReact is to wrap your reactive data sources in autoruns like all the other examples, only in a more structured and automatic way…