jeanpaul62
jeanpaul62

Reputation: 10581

React Navigation: Prevent multiple instances to navigate to same screen

Let's say I have this screen:

screenshot

And when the user clicks on the white tooltip, it redirects to another screen. Sometimes the app lags a little bit, and clicking on the tooltip takes like ~2s to see the screen change. The problem is, during those 2s, the user taps again on this tooltip to make it happen.

And the result I get is that there are two instances of the new screen in my StackNavigator. What I mean is that I see my new screen, but when I click on "Back" I don't return to this 'Hitchhiking Map' screen, but to another instance of that same screen.

If I clicked 5 times on the callout during those 2s, then I need to click 5 times "Back" to return to the Map screen. Any way to prevent that? To put only one instance into the StackNavigator?

I am using React Navigation, more precisely a StackNavigator. Here's my code:

The "click on tooltip" part:

<MapView.Marker
  onCalloutPress={() => this.props.navigation.navigate('spotDetails', { spotId: marker.id })}
/>

My screens:

const HMapNavigator = StackNavigator({
  HMap: { screen: HMapViewContainer },
  spotDetails: { screen: SpotDetailsViewContainer },
});

Upvotes: 4

Views: 8581

Answers (5)

moto
moto

Reputation: 940

Here is a hook that prevents navigating when the screen is not in focus. useIsFocused comes from react-navigation


export const useRootNavigation = (): NavigationProp<RootStackParamList> & PushFunction => {
  const isFocused = useIsFocused();
  const navigation = useNavigation<NavigationProp<RootStackParamList> & PushFunction>();
  const push = useCallback<PushFunction['push']>(
    (...args) => {
      if (isFocused) {
        navigation.push(...args);
      }
    },
    [navigation, isFocused],
  );
  return { ...navigation, push };
};

Upvotes: 0

Sebastian Bałon
Sebastian Bałon

Reputation: 23

In versions 1.x of React Navigation, if you specify an identifier the navigation action will be executed only once. E.g.:

navigate({ routeName: 'someScreen', key: 'someScreen', params: { someParam: 'someValue' } })

More information: https://gist.github.com/vonovak/ef72f5efe1d36742de8968ff6a708985

In versions 2.x and 3.x this is a default functionality.

More info: https://reactnavigation.org/docs/en/navigation-key.html

Upvotes: 0

user2976753
user2976753

Reputation: 966

Save if its opening to control the navigation

  constructor (props) {
    super(props)
    this.state = {
      opening: false
    }
  }

Create a function to control de navigation

  _open (campaign) {
    if (!this.state.opening) {
      this.props.navigation.navigate('Campaign', {campaign})
      this.setState({ opening: true })
      setTimeout(() => {
        this.setState({ opening: false })
      }, 1000)
    }
  }

Call this func from your onpress

<TouchableHighlight underlayColor='transparent' onPress={this._open.bind(this, campaign)}>

Upvotes: 0

matusalem
matusalem

Reputation: 2531

There are many ways how to overcome double navigations.

My solution is adding a key property in navigate object:

this.props.navigation.navigate({ key: 'AnotherScreen', routeName: 'AnotherScreen', params: { ... }})}

Upvotes: 5

Stewart
Stewart

Reputation: 496

The issue of multiple navigations has been reported and there is more detail here.

react-navigation (v1.0.0-beta.7) is in beta and still being built, so until this feature is implemented, you will have to handle the debounce manually.

options

  • disable the button once the navigation starts
  • debouncing in the onPress logic or in the action if you are using redux

lodash provides a useful debounce utility, if you are looking for one.

Upvotes: 7

Related Questions