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