Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

onRegionChangeComplete props Callback triggering infinitely without any user input on Android. #846

Closed
akshay2604 opened this issue Dec 1, 2016 · 15 comments

Comments

@akshay2604
Copy link

i am not using fitToSuppliedMarkers as another issue mentioned, only plain MapComponent . For some reason on Android onRegionChangeComplete is being called infinitely many times. However it is working correctly on IOS.

React native - 0.35
react-native-maps - 0.10.4

@akshay2604
Copy link
Author

if you use region prop along with onRegionChangeComplete , the onRegionChangeComplete is called as a callback. onRegionChangeComplete is called whenever onChange event occurs natively. it could be due to user dragging map, animation on map or even setting up of gps location. If possible another prop should be added like onPanDragComplete so that we get callback only when user drags map and finishes dragging it.

@M3po
Copy link

M3po commented Dec 14, 2016

Did you make it work and how? i am also having problem with infinite loop. Since i need both region and onRegionChangeComplete props

@akshay2604
Copy link
Author

akshay2604 commented Dec 15, 2016

<MapView
          ref={(ref) => { this.map = ref; }}
          style={styles.map}
          initialRegion={this.props.initialRegion}
          loadingEnabled
          onRegionChangeComplete={(region) => {
            // do something 
            }
          }}
        >
</MapView>

This is my new mapComponent. It turns out i was using region prop and was only setting state of region. removing it also works.
I don't know how to use both together. If you look at components/MapView.js there is a particular function

_onChange(event) {
    this.__lastRegion = event.nativeEvent.region;
    if (event.nativeEvent.continuous) {
      if (this.props.onRegionChange) {
        this.props.onRegionChange(event.nativeEvent.region);
      }
    } else if (this.props.onRegionChangeComplete) {
      this.props.onRegionChangeComplete(event.nativeEvent.region);
    }
  }

The _onChange method is called whenever any event happens.If whatever you write in onRegionChangeComplete triggers a call to region prop , region prop in itself triggers an _onChange event which causes onRegionChangeComplete to call. This quickly spirals to an infinite loop each callback trigering each other. You can put logs in MapView.js file to see it for yourself.

I think something like a panDragComplete in this case would do the trick. I am not sure if mapkit or google maps provider provide a native event for this or not. But until then make sure onRegionChangeComplete has code without any side effects. Or if you can't do that, remove region prop, it worked for me

@M3po
Copy link

M3po commented Dec 15, 2016

Thanks for the input i will try to edit the component so i might get something (or will at the do without region change until they make something like you suggested). But as you said we need something like panDragComplete since everytime i click on the marker it triggers onRegionChangeComplete and re-renders. I have to find a workaround. But i think you should leave this issue open.

@meddy
Copy link

meddy commented Jan 25, 2017

I have an app flow like so:

  1. user enters map scene
  2. user's location is passed to region prop of MapView component
  3. user's location is updated
  4. new location is passed to region prop of MapView component
  5. when onRegionChangeComplete is executed, dispatch some actions to update the state, so we can update some markers on the map

On iOS this works normally. OnRegionChangeComplete gets called twice, as you would expect.

On android, as @akshay2604 mentioned, if a re-render or state change happens during an onRegionChangeComplete callback, then onRegionChangeComplete callbacks get called repeatedly causing an infinite loop.

In order to work around this for now I implemented a check in my onRegionChangeComplete callback to determine if the region has actually changed. If not, return early instead of dispatching actions. This at least eliminates multiple HTTP requests or re-renders occurring.

Example Code:

<MapView
        style={style.map}
        onRegionChangeComplete={(region) => {
          const {initialRegion} = this.state;
          
          if (initialRegion && isEqual(initialRegion, region)) {
            return;
          }

          this.setState({initialRegion: region});
          
          // dispatch some actions
        }}
/>

@paulsc
Copy link

paulsc commented Aug 19, 2017

I just had the same problem i.e.:

  • I have a button that changes the map position by changing the "region" state variable
  • The "region" state variable is bound to the region property of MapView
  • so clicking the button triggers a render, which triggers onRegionChangeComplete()
  • onRegionChangeComplete changes some other state variable
  • which triggers a render() call
  • which triggers an onRegionChangeComplete() call again => infinite loop

and what fixed it was setting the "region" state variable in my onRegionChangeComplete() callback. I am now setting it to the argument being passed to onRegionChangeComplete().

I'm not entirely sure why this fixes it, but I assume it has something to do with the state being the same so it doesn't trigger additional render() calls?

I'm curious if this works for anyone else.

Cheers

@augisticz
Copy link

I'm use onRegionChangeComplete={e => this.setState({ region: e })} is work

@IjzerenHein
Copy link
Contributor

Should be fixed by PR #1710

@alvelig
Copy link
Contributor

alvelig commented Dec 13, 2017

I discourage controlling region state. Try this: #209 (comment)

Anyway it should be fixed with the PR above.

@alvelig alvelig closed this as completed Dec 13, 2017
@tsangwailam
Copy link

tsangwailam commented Aug 26, 2018

I found that when you zoom to max. The region from onRegionChangeComplete will be continue changing. The change is so small and about 15/16 significant decimal digits. Is it related to the precision?

@mskuser1
Copy link

@tsangwailam did u find a solution? I have the same problem, it only moves by itself when zoom is on max

@iamshadmirza
Copy link

if you use region prop along with onRegionChangeComplete , the onRegionChangeComplete is called as a callback. onRegionChangeComplete is called whenever onChange event occurs natively. it could be due to user dragging map, animation on map or even setting up of gps location. If possible another prop should be added like onPanDragComplete so that we get callback only when user drags map and finishes dragging it.

Yes, you're right. Adding initialRegion instead of region solves the problem. However, there is one issue, after onRegionChangeComplete is done saving new region, the map is not updating with the new region we just saved. That only works with region prop. Is there any solution to this issue?

@Pratit23
Copy link

if you use region prop along with onRegionChangeComplete , the onRegionChangeComplete is called as a callback. onRegionChangeComplete is called whenever onChange event occurs natively. it could be due to user dragging map, animation on map or even setting up of gps location. If possible another prop should be added like onPanDragComplete so that we get callback only when user drags map and finishes dragging it.

Yes, you're right. Adding initialRegion instead of region solves the problem. However, there is one issue, after onRegionChangeComplete is done saving new region, the map is not updating with the new region we just saved. That only works with region prop. Is there any solution to this issue?

Did you get a fix for this?

@JimTeva
Copy link
Contributor

JimTeva commented Aug 10, 2022

For anyone using GoogleMaps, this is how I fixed it (version 1.2.0):

region={this.state.region}
onRegionChangeComplete={(region, gesture) => {
  if (gesture.isGesture) {
    this.setState({ region });
  }
}}

note: gesture.isGesture indicates if the change was made by user or animation.

@zubbey
Copy link

zubbey commented Jul 3, 2023

For anyone using GoogleMaps, this is how I fixed it (version 1.2.0):

region={this.state.region}
onRegionChangeComplete={(region, gesture) => {
  if (gesture.isGesture) {
    this.setState({ region });
  }
}}

note: gesture.isGesture indicates if the change was made by user or animation.

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests