react-navigation / react-navigation

Routing and navigation for your React Native apps
https://reactnavigation.org
23.6k stars 5.04k forks source link

disable going back once navigate #1815

Closed barron9 closed 7 years ago

barron9 commented 7 years ago

how can I disable back arrow after navigated to another page?

nsisodiya commented 7 years ago

I need this. After Login screen, I sent to Main screen. but customer by mistake press back button and load the Login screen again. very irritating. any solution ?

matthamil commented 7 years ago

You can override the getStateForAction method of the navigator to prevent a user from going back from a screen and/or prevent them from going back to a screen:

const prevGetStateForAction = Navigator.router.getStateForAction;

Navigator.router.getStateForAction = (action, state) => {
  // Do not allow to go back from Home
  if (action.type === 'Navigation/BACK' && state && state.routes[state.index].routeName === 'Home') {
    return null;
  }

  // Do not allow to go back to Login
  if (action.type === 'Navigation/BACK' && state) {
    const newRoutes = state.routes.filter(r => r.routeName !== 'Login');
    const newIndex = newRoutes.length - 1;
    return prevGetStateForAction(action, { index: newIndex, routes: newRoutes });
  }
  return prevGetStateForAction(action, state);
};
bennygenel commented 7 years ago

I tried to prevent app close with the backbutton. is it posible too. I tried the implementation but it doesn't work.

matthamil commented 7 years ago

@bennygenel This prevents the back button from closing the app in my case. Are you using the current version of react-navigation and using the code snippet I posted?

MrHubble commented 7 years ago

@barron9 @nsisodiya does something similar to the below solve the problem for you?

export default class Main extends Component {
  constructor(){
    super();
    this.state = {
    }
  }
  static navigationOptions = {
    headerLeft: null
  }  
Buthrakaur commented 7 years ago

@nsisodiya did you try to replace the navigation state when moving from login to main screen instead of standard navigation?

      const resetAction = NavigationActions.reset({
        index: 0,
        actions: [
          NavigationActions.navigate({
            routeName: "MainScreen",
            params: { user }
          })
        ]
      });
      this.props.navigation.dispatch(resetAction);
abhi-govula commented 7 years ago

@Buthrakaur I have a stack navigation with Home, Login, Main(Tab Navigation)
When the user opens the app he sees the Home Screen, from there he taps Login to go to the Login Screen i added the code you gave in the function after successful authentication in the Login Screen and i see the Home Screen briefly before i get redirected to Main

atomoil commented 7 years ago

I have a screen with some data on it, and I want to save the data in draft form when the user taps 'back'.

I found this thread while trying to work out how to implement this and so adding this note here for anyone else in the same position, as it took a while to work out the solution.

I used the Router's https://reactnavigation.org/docs/routers/api#getStateForAction-action-state

const Navigation = StackNavigator({
  // screens defined here
})

const prevGetStateForAction = Navigation.router.getStateForAction;

Navigation.router.getStateForAction = (action, state) => {

  // don't allow back from 'EditReport'
  if (action.type === 'Navigation/BACK' && state && state.routes[state.index].routeName === 'EditReport') {
    // additional logic here to save draft data
    // used this.props.navigation.setParams in the Screen
    // and state.routes[state.index].params here
    return state;
  }

  return prevGetStateForAction(action, state);
};

To prevent Android from exiting the app I also had to add this to MainActivity.java:

    @Override
    public void invokeDefaultOnBackPressed() {
        //moveTaskToBack(true);
    }
ThaJay commented 6 years ago
function confirmLogoutAlert (logout) {
  Alert.alert(
    strings.logOutVerb,
    strings.confirmLogOut,
    [
      {text:strings.cancel, onPress:() => console.log('Cancel logout')},
      {text:ok, onPress:logout}
    ]
  )
}

function processBackPress () {
  const scene = navigate.getCurrentRoute().routeName
  switch (scene) {
    case LOGIN:
      return
    case DRAWER:
      store.dispatch(actionCreators.setDrawerOpen(false))
      return true
    case SETTINGS:
      confirmLogoutAlert(logout)
      return true
  }

  return navigate.back()
}

BackHandler.addEventListener('hardwareBackPress', processBackPress)

This plus use reset() instead of navigate() if you want to disable back from headerLeft on the next route

pkhien95 commented 6 years ago

@matthamil I tried your code but it doesn't work (tested on iOS). Seem like getStateForAction was called after I swiped Home screen to the left.

SirPhemmiey commented 6 years ago

@Buthrakaur's solution did the trick

bexuma commented 6 years ago

https://reactnavigation.org/docs/en/auth-flow.html

chirag773 commented 5 years ago

I need this. After Login screen, I sent to Main screen. but customer by mistake press back button and load the Login screen again. very irritating. any solution ?

hey do you solve that problem I'm getting same issue with my app.

Johncy1997 commented 5 years ago

I solved this by following:

const defaultGetStateForAction = PrimaryNavigation.router.getStateForAction;
PrimaryNavigation.router.getStateForAction = (action, state) => {
  if (Platform.OS === "android") {
    const screen = state ? state.routes[state.index] : null;
    if (
      action.type === NavigationActions.BACK &&
      screen &&
      (screen.routeName === "Register" ||
        screen.routeName === "OwnerDashboard" ||
        screen.routeName === "LandingPage" ||
        screen.routeName === "OptionPage" ||
        (screen.routeName === "loginStack" && screen.index == 0) 
        || (screen.routeName === "driverStack" &&
          screen.index == 0 &&
          screen.routes[screen.index].index == 0 )
        || (
          screen.routeName === "ownerStack" &&
          screen.index == 0 &&
          screen.routes[screen.index].index == 0
        )
      )
    ) {
      Alert.alert(
        "Are you sure",
        "You want to exit the App",
        [
          {
            text: "Cancel",
            onPress: () => console.log("Cancel Pressed"),
            style: "cancel"
          },
          { text: "OK", onPress: () =>{ BackHandler.exitApp() }}
        ],
        { cancelable: false }
      );
      console.log("action",action,"state",state);
      return null;
    }
    else{
      return defaultGetStateForAction(action, state);
    }
  }
  else{
    return defaultGetStateForAction(action, state);
  }
};

Its working fine to my desire.

junaidijaz commented 5 years ago

@nsisodiya if you are using react native navigator then on login button click just use this code this.props.navigation.replace('home')

4sagar commented 5 years ago

@nsisodiya if you are using react native navigator then on login button click just use this code this.props.navigation.replace('home')

This will work in case of react-navigation as well.

otskarli commented 4 years ago

@nsisodiya if you are using react native navigator then on login button click just use this code this.props.navigation.replace('home')

This will not work on react-navigation v5

this.props.navigation.navigate("User") works this.props.navigation.replace("User") cant find screen

mschipperheyn commented 4 years ago

@JsonGuy one limitation I found earlier on replace is that it doesn't allow you to switch navigator like navigate does. Not sure if that is your case.

ngankt2 commented 4 years ago

@nsisodiya if you are using react native navigator then on login button click just use this code this.props.navigation.replace('home')

I have 3 screens, the application will load screen A first time.

How to fix this error?

hanayashiki commented 4 years ago

@nsisodiya if you are using react native navigator then on login button click just use this code this.props.navigation.replace('home')

This will work in case of react-navigation as well.

This is only useful if you don't have screen other than login. If there's an starter screen, user can still navigate back.

hrahul2605 commented 4 years ago

If anyone is still looking for a method to do this, you can refer to this part of the docs for react navigation https://reactnavigation.org/docs/navigation-prop/#dispatch

I modified the code just a little, my code goes like this

navigation.dispatch((state) => {  
    const routes = [ ...state.routes]; 

    return CommonActions.reset({  
        /* removed the ...state line from here which technically 
           removes all the history from my navigation state,
           but the routes are still available as i have declared the routes array*/
        routes,  
        index: 0, /* set the index value to 0 because my "Home" screen is at 0 index. 
        So whichever screen you want to go, just specify the index. 
        You can check your screens index by console.log(state.routes) */
    });  
});
crisnastics commented 4 years ago

@nsisodiya si está utilizando el navegador nativo reaccionar, luego haga clic en el botón de inicio de sesión solo use este código this.props.navigation.replace('home')

navigation.replace('Login') ---> this solution is ok. Redirect the screen and avoid sliding goback on iOS at least

smusmanobjects commented 11 months ago

You can use this code:

this.props.navigation.dispatch( CommonActions.reset({ index: 1, routes: [ { name: 'YourDesiredScreen' } ], }) );

github-actions[bot] commented 11 months ago

Hey! This issue is closed and isn't watched by the core team. You are welcome to discuss the issue with others in this thread, but if you think this issue is still valid and needs to be tracked, please open a new issue with a repro.