列出地理位置区域

时间:2017-06-25 03:09:24

标签: listview firebase react-native geofire

我正在尝试显示属于当前位置的地理范围内的商家列表。我遇到的问题是数据源似乎没有填充任何行。

import React from 'react'
import { View, ListView, Image, Text, ActivityIndicator } from 'react-native'
import ParallaxScrollView from 'react-native-parallax-scroll-view'
import AlertMessage from '../Components/AlertMessage'
import Geocoder from 'react-native-geocoder'
import { Colors } from '../Themes/'
import { connect } from 'react-redux'
import MerchantRow from '../Components/MerchantRow'
import { firebaseApp } from '../Config/AppConfig'
const GeoFire = require('geofire')

// Styles
import styles from './Styles/MerchantListStyle'

class MerchantList extends React.Component {

  watchID: ?number = null;

  constructor (props) {
    super(props)
    this.state = {
      dataSource: new ListView.DataSource({
        rowHasChanged: (row1, row2) => row1 !== row2
      }),
      result: '',
      city: 'you'
    }
    // Get references to several nodes we will need
    rootRef = firebaseApp.database().ref();
    merchantsRef = rootRef.child('merchants');
    geofireRef = rootRef.child('locations');
    this.geoFire = new GeoFire(geofireRef)
  }

  componentDidMount () {
    navigator.geolocation.getCurrentPosition(
      (position) => {
      },
      (error) => alert(JSON.stringify(error)),
      {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
    )

    this.watchID = navigator.geolocation.watchPosition((position) => {
      var lat = position.coords.latitude;
      var lng = position.coords.longitude;

      Geocoder.fallbackToGoogle('AIzaSyCPVaJK7Sx-Uv6X76508NUlrpF3YJBqgrk')

      let ret = Geocoder.geocodePosition({lat, lng}).then((res)=>
      {
        city = res['0'].locality
        this.setState({ city: city })
      })

      let radius = 40 // 40km
      let currentLocation = [
        position.coords.latitude,
        position.coords.longitude
      ]

      let geoQuery = this.geoFire.query({center: currentLocation, radius})
      var merchants = [];
      // For every key which matches our GeoQuery...
      geoQuery.on('key_entered', function(key) {
        // ... look up the merchant data for that key ...
        // console.log(key)
        merchantsRef.child(key).once('value').then(function(snapshot) {
          // ... and add it to the matches array
          merchants.push(snapshot.val())
          console.log(merchants)
          this.setState({
            loading: false,
            dataSource: this.state.dataSource.cloneWithRows(merchants)
          })
        }).catch(function(error) {
          console.log('Error fetching merchant data:', error)
        })
      })
    })
  }

  componentWillUnmount () {
    navigator.geolocation.clearWatch(this.watchID)
  }

  _renderRow (item) {
    return (
      <MerchantRow data={item} />
    )
  }

  _noRowData () {
    return this.state.dataSource.getRowCount() === 0
  }

  render () {
    return (
      <View style={styles.container}>
        <ListView
          dataSource={this.state.dataSource}
          renderRow={this._renderRow.bind(this)}
          enableEmptySections
          pageSize={15}
          renderScrollComponent={props => (
            <ParallaxScrollView
              backgroundColor={Colors.background}
              contentBackgroundColor={Colors.background}
              parallaxHeaderHeight={250}
              renderBackground={() => (
                <Image
                  style={styles.photo}
                  source={{uri: this.props.photo}}
                  defaultSource={require('../Images/Merchant_Header.png')}
                />
              )}
              renderForeground={() => (
                <View key='parallax-header' style={styles.parallaxHeader}>
                  <Text style={styles.title}>
                    {'Choose a café near\n' + this.state.city + ' to start\n your order'}
                  </Text>
                </View>
              )}
            />
          )}
        />
        <AlertMessage title='Nothing to See Here, Move Along' show={this._noRowData()} />
      </View>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    // ...redux state to props here
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(MerchantList)

1 个答案:

答案 0 :(得分:1)

出现此问题的原因是您使用的是普通回调函数,而不是使用使用胖箭头的ES6函数。

  geoQuery.on('key_entered', function(key) {
    // ... look up the merchant data for that key ...
    // console.log(key)
    merchantsRef.child(key).once('value').then(function(snapshot) {
      // ... and add it to the matches array
      merchants.push(snapshot.val())
      console.log(merchants)
      this.setState({
        loading: false,
        dataSource: this.state.dataSource.cloneWithRows(merchants)
      })
    }).catch(function(error) {
      console.log('Error fetching merchant data:', error)
    })
  })

this对象应引用this.state.dataSource.cloneWithRows(merchants)中的班级。但是,在Javascript中,正常回调function() {}将创建并绑定其自己的this对象而不是其父对象,这意味着this.state.dataSource.cloneWithRows(merchants)现在无效。为了防止这种情况,您应该使用ES6函数语法,它不会进行任何this绑定。

您的更新代码应如下所示:

  geoQuery.on('key_entered', (key) => { // Using fat arrows
    // ... look up the merchant data for that key ...
    // console.log(key)
    merchantsRef.child(key).once('value').then((snapshot) => { // here too!
      // ... and add it to the matches array
      merchants.push(snapshot.val())
      console.log(merchants)
      this.setState({
        loading: false,
        dataSource: this.state.dataSource.cloneWithRows(merchants)
      })
    }).catch((error) => { // If you are planning to use this here
      console.log('Error fetching merchant data:', error)
    })
  })

如果要使用普通的回调函数语法而不是ES6版本,可以在函数外部创建对此的引用,并使用内部的新引用。在这种情况下,您的代码应如下所示:

const that = this; // created a reference!      
     geoQuery.on('key_entered', function(key) {
        // ... look up the merchant data for that key ...
        // console.log(key)
        merchantsRef.child(key).once('value').then(function(snapshot) {
          // ... and add it to the matches array
          merchants.push(snapshot.val())
          console.log(merchants)
          that.setState({ // Use the reference here!
            loading: false,
            dataSource: that.state.dataSource.cloneWithRows(merchants) // Here too!
          })
        }).catch(function(error) {
          console.log('Error fetching merchant data:', error)
        })
      })