React Navigation: Navigate Back To Root using Navi

2019-02-02 23:00发布

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);
}

4条回答
2楼-- · 2019-02-02 23:14

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!
查看更多
看我几分像从前
3楼-- · 2019-02-02 23:21

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

查看更多
Melony?
4楼-- · 2019-02-02 23:33

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);
};

nov-05-2017 11-34-07

查看更多
来,给爷笑一个
5楼-- · 2019-02-02 23:39

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!

查看更多
登录 后发表回答