maps: MapView's onUserLocationUpdate doesn't seem to fire

Describe the bug MapView’s onUserLocationUpdate doesn’t seem to fire.

To Reproduce

    onUserLocationUpdate = (location) => {
     console.log('location',location);
    }
    render() {
      return (
          <MapboxGL.MapView
            animated
            ref={c => this.map = c}
            styleURL={this.props.theme.styleURL}
            onUserLocationUpdate={this.onUserLocationUpdate}
            onPress={this.onPress}
            logoEnabled={false}
            compassEnabled={false}
            pitchEnabled={false}
            onRegionWillChange={this.onRegionWillChange}
            style={{ flex: 1 }}
            onDidFinishLoadingMap={this.onDidFinishLoadingMap}
            onDidFinishRenderingMap={this.onDidFinishRenderingMap}
            onDidFinishRenderingMapFully={this.onDidFinishRenderingMapFully}
            onDidFinishLoadingStyle={this.onDidFinishLoadingStyle}
            onUserLocationUpdate={this.onUserLocationUpdate}
          >
            <MapboxGL.UserLocation visible={true} renderMode="custom">
              <MapboxGL.CircleLayer id="mapboxUserLocationPluseCircle" style={layerStyles.normal.pulse} />
              <MapboxGL.CircleLayer id="mapboxUserLocationWhiteCircle" style={layerStyles.normal.background} />
              <MapboxGL.CircleLayer id="mapboxUserLocationBlueCicle" aboveLayerID="mapboxUserLocationWhiteCircle" style={layerStyles.normal.foreground} />
            </MapboxGL.UserLocation>

            <MapboxGL.Camera
              followUserLocation={this.state.currentTrackingModeIsFollowing}
              followUserMode="course"
              onUserTrackingModeChange={this.onUserTrackingModeChange}
            />

          </MapboxGL.MapView>
     )
   }

Expected behavior Expected onUserLocationUpdate to fire the callback

Screenshots N/A

Versions (please complete the following information):

  • Platfrom: iOS
  • Device: iPhone 7 Plus
  • OS: iOS 12.3.1.
  • SDK Version: N/A
  • react-native-mapbox-gl Version: 7.0.0-rc3
  • React Native Version 0.56.0

Additional context Just doesn’t seem to fire. I searched the repo’s source code and not sure why it could be not working - seems like onUserLocationUpdate is still a prop of MapView, not Camera. Not quite sure if it’s because of some props i’m passing in. Was working fine 6.1.2

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 3
  • Comments: 26 (18 by maintainers)

Most upvoted comments

We should create a throttle control for this and onRegionIsChanging similar to ScrollView onScroll. The throttle should happen on native side to prevent unnecessary bridge activity.

Happy to see a PR for this. The RN core ScrollView can be a good source of inspiration for this code.

On Wed, 30 Oct 2019 at 19:39, Richard Lindhout notifications@github.com wrote:

Probably, (maybe by only checking difference in long / lat) but I’m doing some fairly heavy things after a location update, so I don’t want to do that every second. I think somethings like this is the only way since it keeps firing location events even if my device does not do anything.

But I think this should be handled in te library in the native thread, since I think all the debounces are fairly memory heavy. Have no proof for that though 😃

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/react-native-mapbox-gl/maps/issues/246?email_source=notifications&email_token=ABLAPW5MGSAC2IK563FHBHLQRHIELA5CNFSM4IDSMAX2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECVKYII#issuecomment-548056097, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABLAPW5W4FLFZPADJSIC52TQRHIELANCNFSM4IDSMAXQ .

Interestingly I’ve noticed, that it not always fires like crazy, sometimes it’s less frequent, sometimes more… I also only monitor it via remote debugger when in the office.

You should log it, it’s extreme how much update

My HOC component (I have a shared codebase with react-native-web)

import React, { useState, useCallback } from 'react'
import { useDebouncedCallback } from 'use-debounce'

import { distance } from './helpers'

export default function MapUserLocationHOC(WrappedComponent) {
  function Enhanced({ onUserLocationUpdate, ...rest }) {
    const [previousLocation, setPreviousLocation] = useState(null)

    const onUpdateCoords = useCallback(
      ({ coords }) => {
        if (!coords) {
          // console.log('no args to debounced location update')
          return
        }

        let needsUpdate = false
        if (previousLocation) {
          const dist = distance(previousLocation, coords, 'CM')
          if (dist > 30) {
            needsUpdate = true
          }
        } else {
          needsUpdate = true
        }

        if (needsUpdate) {
          setPreviousLocation(coords)

          // let other component know user location has changed
          onUserLocationUpdate && onUserLocationUpdate(coords)
        }
      },
      [previousLocation, setPreviousLocation, onUserLocationUpdate]
    )
    const [onDebouncedUpdate] = useDebouncedCallback(
      // function
      onUpdateCoords,
      // delay in ms
      600,
      { maxWait: 2000 }
    )

    return <WrappedComponent {...rest} onDebouncedUpdate={onDebouncedUpdate} />
  }
  return Enhanced
}

// https://www.geodatasource.com/developers/javascript
export function distance(location1, location2, unit) {
  const lat1 = location1.latitude
  const lon1 = location1.longitude

  const lat2 = location2.latitude
  const lon2 = location2.longitude
  if (lat1 === lat2 && lon1 === lon2) {
    return 0
  } else {
    var radlat1 = (Math.PI * lat1) / 180
    var radlat2 = (Math.PI * lat2) / 180
    var theta = lon1 - lon2
    var radtheta = (Math.PI * theta) / 180
    var dist =
      Math.sin(radlat1) * Math.sin(radlat2) +
      Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta)
    if (dist > 1) {
      dist = 1
    }
    dist = Math.acos(dist)
    dist = (dist * 180) / Math.PI
    dist = dist * 60 * 1.1515

    if (unit === 'K') {
      dist = dist * 1.609344
    }
    if (unit === 'M') {
      dist = dist * 1.609344 * 1000
    }
    if (unit === 'CM') {
      dist = dist * 1.609344 * 1000 * 100
    }
    if (unit === 'N') {
      dist = dist * 0.8684
    }
    return dist
  }
}

@ferdicus you have to debounce this onUpdate since it fires at least every second and without any movement.

It not there I think

I use the UserLocation

<Mapbox.UserLocation visible={true} onUpdate={onUpdate} />

With that on update you need to check if the distance between the old and the new point is greater than … or else you have an update every second.