Reputation: 163
I'm re-building an app I previously made in Swift with React Native. It is a simple map with pins at this stage. It renders with dummy data, and I can query for the data successfully from Parse, but I don't know how to map it without failure, as I am having trouble using syntax to check for whether the query has completed. The crux, I believe, is in understanding React states and Javascript/JSX syntax - guidance appreciated.
Relevant code:
var testApp = React.createClass({
mixins: [ParseReact.Mixin],
getInitialState() {
return {
mapRegion: {
latitude: 22.27,
longitude: 114.17,
latitudeDelta: 0.2,
longitudeDelta: 0.2,
},
annotations: null,
isFirstLoad: true,
};
},
componentDidMount: function() {
this.setState({isLoading: true});
},
render() {
// console.log(this.data.sites); // this works without the below
return (
<View>
<MapView
style={styles.map}
region={this.state.mapRegion || undefined}
annotations={this.state.data.sites.map(function(site) { // error
var pinObj = {};
pinObj.latitude = site.Lat;
pinObj.longitude = site.Long;
pinObj.title = site.Name;
pinObj.subtitle = site.Address;
return pinObj;
}) || undefined}
/>
</View>
);
},
observe: function(props, state) {
var siteQuery = (new Parse.Query('Site')).ascending('Name');
return state.isLoading ? {sites: siteQuery} : null;
},
});
Error produced: 'Cannot read property 'sites' of undefined'. This is clearly because I'm trying to iterate over the sites data before the query has returned. How can I modify my syntax to take care of this? Define a map in a separate function?
Upvotes: 0
Views: 246
Reputation: 20097
Certainly the data might not yet be available when you render the component.
The ParseReact mixin /observe works in the way that the observe method is called only after parse's query returns. So the sequence of methods is:
getInitialState()
componentDidMount()
... here parse's query starts I believe
render()
.... here some time passes
observe() // here the query returns the data
.... Parse's ParseReactMixin updates state via this.setState({data: returnedValue})
.... changed state triggers rerender
render()
Render is called twice - once before the data is loaded and second time after. What you should do is to check the state and display some loading state (in our case most likely map with some loading indicator. For example:
render(): function {
if(this.state.isLoading) {
return <View><Map ..... (no annotations) ></Map><ActivityIndicatorIOS/></View>
} else {
return <View><Map .... (with annotations)></Map></View>
}
}
Alternatively you can define some "getAnnotations()" method that will return either the real annotation or the dummy (or empty ones) if the real ones are not available. You can then use it as
...
annotations={this.getAnnotations()}
...
and adding the right combination of parameters on ActivityIndicatorIOS (animating = {this.state.isLoading} hidesWhenStoped=true}
Upvotes: 1