Hoosh
Hoosh

Reputation: 163

How do I refactor a response from Parse (or any data source) in React or React Native?

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

Answers (1)

Jarek Potiuk
Jarek Potiuk

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

Related Questions