React Navigation: Navigate Back To Root using Navi

2019-02-02 22:42发布

问题:

Say I've navigated through 4 screens in my StackNavigator App and now I want to go back to the first screen. There seems to be three different ways to do this and they do navigate to where I want to do, however each way has an animation that cycles through each previous screen.

Is there a clean way to navigate from SCREEN_D to SCREEN_A?

In other words, I don't want to see SCREEN_C and SCREEN_B a split of a second before seeing SCREEN_A when navigating backwards from SCREEN_D

navigation.navigate(SCREEN_A);
...
navigation.navigate(SCREEN_B);
...
navigation.navigate(SCREEN_C);
...
navigation.navigate(SCREEN_D);

Three ways to do this:

1.

return this.props.navigation
               .dispatch(NavigationActions.reset(
                 {
                    index: 0,
                    actions: [NavigationActions.navigate({ routeName: 'SCREEN_A'})]
                  }));

2.

 const {SCREEN_B_KEY} = this.props.navigation.state.params
 this.props.navigation.goBack(SCREEN_B_KEY)

3.

const defaultGetStateForAction = Navigation.router.getStateForAction;

Navigation.router.getStateForAction = (action, state) =>{
  if(action.type === "Navigation/BACK"){
    const routes = [
      {routeName: 'First'},
    ];
    return {
      ...state,
      routes,
      index: 0,
    };
  }
  return defaultGetStateForAction (action,state);
}

回答1:

Here's a quick fix. This will remove ALL transitions when navigating (forward or backward).

const Nav = StackNavigator({
  Screens
},{
  transitionConfig,
  navigationOptions
});

in transitionConfig add this:

const transitionConfig = () => ({
    transitionSpec: {
      duration: 0,
      timing: Animated.timing,
      easing: Easing.step0,
    },
  })

The transitionConfig is a function that returns an object that overrides default screen transitions. https://reactnavigation.org/docs/navigators/stack

  • if someone knows a way to change animations on single navigation, I'd love to hear how!


回答2:

You can do this by using the popToTop method from the Navigation prop. Also, if you are using redux, you should update your Redux integration.

Hope this helps!



回答3:

Also spent some time on this, let me sum up what I discovered, there are multiple solutions/workarounds for this:

1) Use CardStackStyleInterpolator

The pull request mentioned by Cristiano Santos seems to be merged. So you can load the CardStackStyleInterpolator with this import:

import CardStackStyleInterpolator from 'react-navigation/src/views/CardStack/CardStackStyleInterpolator'

To apply it like this:

const YourStackNavigator = StackNavigator({
    Screen1: { screen: Screen1 },
    Screen2: { screen: Screen2 },
}, {
    transitionConfig: () => ({
        screenInterpolator: (props) => CardStackStyleInterpolator.forHorizontal(props)
    })
});

In my case, I just jump to the next screen like:

this.props.navigation.navigate('Modal_AddGoodClass');

But in my reducer, I reset the navigator when the Modal_AddGoodClass screen is triggered:

const NewExportReceiptNavigationReducer = (state, action) => {
    // Default stuff

    let newStateBuffer = newState || state;

    if (action) {
        if (action.type === 'Navigation/NAVIGATE') {
            if (action.routeName === 'Modal_AddGoodClass') {
                newStateBuffer = {
                    index:  0,
                    routes: [
                        newStateBuffer.routes[newStateBuffer.routes.length - 1]
                    ]
                };
            }
        }
    }

    return newStateBuffer;
};

module.exports = NewExportReceiptNavigationReducer;

This works pretty well, except the fact, that still a "back" animation is used instead of a "forward" one.

You can also find here some example code that uses CardStackStyleInterpolator.

2) Overwrite getStateForAction:

As Fendrian mentioned here you can overwrite getStateForAction of your router to avoid the navigator to go back. This seems to work except for the "swipe back" gesture on iOS:

Nav = StackNavigator(navScreens, navOptions);
const defaultGetStateForAction = Nav.router.getStateForAction;
Nav.router.getStateForAction = (action, state) => {
  if (
    state &&
    action.type === NavigationActions.BACK &&
    (
      state.routes[state.index].routeName === 'Login' ||
      state.routes[state.index].routeName === 'Main'
    )
  ) {
    // Returning null indicates stack end, and triggers exit
    return null;
  }
  return defaultGetStateForAction(action, state);
};



回答4:

This is my working solution for reset back to home (root) without creating new route

if(this.categoriesNav.state.nav.index >0){
    let k = this.categoriesNav.state.nav.routes[1].key;
    this.categoriesNav.dispatch(NavigationActions.back({key: k})); }

categoriesNav is referenced to my stack navigator