Closed Twinski closed 7 years ago
Have you tried using a routeName to go back to, i.e. goBack('Main')
?
I had same problem. After doing quite a lot of research, I still couldn't find any clean & elegant solution that I could deeply understand.
So I ended up putting multiple "steps" into one single screen, so goBack() from any step of this single screen would exit the entire flow.
The implementation is actually not too bad, as I could 100% understand what's going on there and structure the code in a maintainable way :)
The Navigate/BACK
action can take a key
, which can specify exactly which screen to go back from. Each screen can see its key by looking at this.props.navigation.state.key
@ericvicenti
Thanks for the suggestion. I'll have a look at it.
@Twinski Were you able to solve this? I have a similar situation -- a tab navigator inside a stack navigator and I need to go back/pop the top-level stack navigator from any of the screens associated with the tabs in the nested tab navigator, and none of the things I've tried have worked... so I'm just wondering how you were able to ultimately solve your problem.
I didn't give a try to be honest. Right now I switched to wix's library for native navigation. Airbnb also released their navigation library.
I would try to solve some of your problems in combination with Redux? I wrote my own tab navigator to have a complete custom tabbar (with a big plus button in the middle) & to be able to select a tab from anywhere in the app.
ā Dispatch action "NAVIGATE_TO_TAB" with { tabbar: "home", tab: "profile" } as payload for example. Hope this gives you some inspiration to tackle your problem ;)
I can't goback() even with a key
I'm facing a similar issue. this is my current setup
const AppNavigator = StackNavigator({
Login: { screen: LoginScreen },
Splash: { screen: SplashScreen },
Timeline: { screen: TimelineNavigator },
});
const TimelineNavigator = StackNavigator({
Timeline: { screen: TimelineScreen },
Task: { screen: TaskNavigator },
});
const TaskNavigator = StackNavigator({
Task: { screen: TaskScreen },
});
The route flow I have in application
Splash -> Reset to Timeline -> Navigate to Task -> Go back to Timeline
For the last step, I'm trying goBack()
& goBack('Task')
from TaskScreen
but it does not go back to TimelineScreen
. Am I missing something here?
@dhruvparmar372 According to the NOTE in the doc
a navigator's navigation prop may not have the helper functions (navigate, goBack, etc); it may only have state and dispatch.
So, use dispatch instead of goBack when the goBack not working. Example:
this.props.navigation.dispatch(NavigationActions.back())
See the example here to learn more.
@Germinate That did work. But may I ask why goBack() didn't work?
I'm having trouble with something similar. The set up is a StackNavigator nested within a TabNavigator within a StackNavigator. It workes perfectly except navigating to the outermost stacks initial screen.
I tried the
this.props.navigation.dispatch(NavigationActions.back(<ScreenName>))
but I get an error like
In this environment the sources for assign MUST be an object.This error is a performance optimization and not spec compliant.
What is happening?
Edit:
Tried to use the key suggested by @ericvicenti.
let goBack = NavigationActions.back({ key: key });' 'this.props.navigation.dispatch(goBack);
where the key is the key of the second screen of the outermost StackNavigator. This does nothing.
@Germinate's solution worked for me.
I have exactly same issue with @Twinski. Any solutions?
import { NavigationActions } from 'react-navigation'
const backAction = NavigationActions.back({
key: null
})
this.props.navigation.dispatch(backAction);
This should do the trick!
@sigridbra I also faced similar problem. I solved it as follows:
navigation.dispatch(
NavigationActions.reset({
index: 1,
actions: [
NavigationActions.navigate({ routeName: 'Router' }),
NavigationActions.navigate({ routeName: 'ProfilePage' }),
],
}),
)
Refer docs
@Twinski Found this Issue when looking for a solution. @Germinate's solution worked for going back one screen at a time, but I needed to reset back many screens. Ultimately this solution worked for my similar use case: https://github.com/react-community/react-navigation/issues/1127#issuecomment-295841343
I was also a little confused by the API here. It seems like the most common use case of wanting to go back to something other than the immediately previous screen (which you can get with just NavigationActions.back()
is to go back to a given screen in the navigation state rather than back from. Here's some untested, use at your own risk, code.
function getKeyToGoBackToRouteName(
state: NavigationState,
routeName: string
) {
// reverse the routes so we go back to the most recent route with name=RouteName
const reversedRoutes = state.routes.slice(0).reverse();
const index = reversedRoutes.findIndex(r => {
return (
// Check if the route is the one we want
r.routeName === routeName ||
// Or if this is a nested Navigator route, recursively check to see if
// its children match
!!(r.routes && getKeyToGoBackToRouteName(r, routeName))
);
});
// If we didn't find the route, then return immediately
if (index === -1) return null;
// We want the key of the route _after_ routeName so that when we go back from
// key, we are at routeName
// Since we have reversed the routes, later routes have smaller indices
const route = reversedRoutes[index - 1];
return route ? route.key : null;
}
NavigationActions.back(getKeyToGoBackToRouteName(navigationState, 'RouteToBeActiveAfterThisAction'));
I did all that everyone above say to do. After read (react navegation code), i understood and now I can do that !
In my case i have 3 router : A -> B -> C and i want to go from C to A directly. So i do this:
on constructor in B.js:
constructor(props) {
super(props);
this.props.navigation.state.key = 'BScreen'; //set the key's name that you want
}
on render in C.js:
render(){
const { goBack } = this.props.navigation;
return(
<Button onPress={() => {goBack('BScreen')}}>Go BACK!</Button>
);
}
FIX BUG ( creating screen B twice) (RECOMEND do this):
on open screen C in B.js:
this.props.navigation.navigate('CScreen', {keyBScreen: this.props.navigation.state.key});
on back button in C.js:
render(){
const { params } = this.props.navigation.state;
const { goBack } = this.props.navigation;
return(
<Button onPress={() => {goBack(params.keyBScreen)}}>Go BACK!</Button>
);
}
@Germinate It did not work for me. Always returns to the initial route. I wanted to go back to the previous page.
@MatheusLima7 see my comment
@MatheusLima7 Your solution worked for me! Here's sample code:
const RootNavigator = StackNavigator({
Main: {
screen: MainNavigator,
},
Something: {
screen: SomethingNavigator,
},
});
const SomethingNavigator = StackNavigator({
Step1: { screen: Step1 },
Step2: { screen: Step2 },
Step3: { screen: Step3 },
}
export default RootNavigator;
My code is set up to conditionally go to either Step2 or Step3 from Step1. The behavior I want is for the back gesture to navigate to Step1 from either Step3 or Step2. Step2 already goes back to Step1 because of the stack order.
By using your suggestion, and setting the navigation state key to Step2 in Step3's constructor, the navigation works as I wanted!!
export default class Step3 extends React.Component {
constructor(props) {
super(props);
this.props.navigation.state.key = 'Step2';
}
...
}
Now, swiping back from either Step2 or Step3 it always pops me back to Step1.
Thanks!
@Guihgo Thanks man, your code was an easy fix to my problem! However, i'm just wondering why it works?
@Guihgo I just wanted to return a method to a previous page in a simple way. There are routes with parameters that would cause me many problems. GoBack for me would work as a simple return to the previous page.
Just in case anyone needs a solution, goBack(null)
did the trick for me.
Screen.navigationOptions = ({ navigation }) => ({
headerRight: (
<TouchableOpacity
onPress={() => navigation.goBack(null)}
>
<Text>Back</Text>
</TouchableOpacity>
),
});
thanks to the response of @Guihgo I've found what I needed to solve the problem: You got the screens A, B, C and D; and you navigate from A->B->C->D. Now you're on D and wants to go back to A. reactnavigation's doc gives you a few ways to do this:
navigation prop goBack
linkthis.props.navigation.goBack('B')
Back NavigationAction
linkthis.props.navigation.dispatch(
NavigationActions.back({key:'B'})
)
We're using the key = 'B', because only the screen B can go back to the screen A. But the code above doesn't work, why? Because the key of the screen B is not 'B'; the key is another alphanumeric string which we don't know. So, to solve this, what we have to do is to set the key = 'B' in the constructor of screen B, as @Guihgo did in his comment:
constructor(props) {
super(props)
this.props.navigation.state.key = 'B'
}
Then, you could navigate to screen A from screen D, or C or any other screen. This worked for me, and I hope this could help.
Check out this thread for a DismissableStackNavigator: How to dismiss modal containing a StackNavigator
And a second comment noting an option to add the dismiss
method to screenProps
@Guihgo I try the code to fix bug ( creating screen B twice) , but it's not work , my react-navigation version is v1.5.8, how to fix ? why set key will render twice ?
@LadyBethJ @Guihgo
I am using:
this.props.navigation.goBack('B')
and
this.props.navigation.state.key = 'B' // Tried in constructor and componentDidMount(), same result
However, I keep getting this yellow box error:
Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the B component
And also it does not run my componentWillUnmount()
function.
Does anyone know why I am getting this? The goBack navigation works great but why does this happen?
I just spent a whole afternoon with this issue and solved it pretty simply.
My case: RootNav |-----TabNavigator |-----------TabA |-----------TabB |-----------TabC |-----StackNavigator |-----------StackA |-----------StackB
From TabC I launched stackNavigator in modal mode. I then navigated from StackA to StackB and wanted to dismiss my modal and get back to TabC.
I ended up accomplishing this with:
this.props.navigation.dispatch(NavigationActions.popToTop()); this.props.navigation.dispatch(NavigationActions.back());
@wachunei this.props.navigation.goBack(null) will fire constructor and componentDidMount, and fire componentWillUnmount improperly
@kevinscience can you elaborate? Because so far navigation.goBack(null) seems to be the only solution that shows the intended behavior.
const currentRoutes = screenProps.rootNavState.routes;
const currentTrustedContactRoutes = currentRoutes.find(route =>
route.routeName === 'Navigator',
);
const key = currentTrustedContactRoutes.routes.find(route => route.routeName === 'Screen').key;
navigation.goBack(key); // moved one back from 'Screen'
Thanks @Germinate :)
goBack(null) is the winner.
navigation.goBack(null)
make my application freeze completly on android after i migrate from V1 to V2
i use now navigation.goBack()
this.props.navigation.dispatch(NavigationActions.back())
. It Works for me
Thanks, @wachunei :)
@Germinate You rock!!!
@LadyBethJ @Guihgo , Can you tell me how to pass params with goBack?. i need to pass some params from ScreenC to ScreenA
@ananth10
const resetAction = NavigationActions.reset({ index: 0, actions: [ NavigationActions.navigate({ routeName: 'ScreenA', params: { foo: 'bar' } }), ], });
@nikilarigela I dont want o reset stack, all i need is go back to Screen A from Screen C. it is working now . i have followed @Guihgo solution. but i need to pass some params to Screen A. if i reset stack and do navigate Screen A then all data reloading from server again. so i dont want to happen this.
@ananth10 ok got it. Thanks
navigation.goBack()
is not working properly as you can see here: https://github.com/proyecto26/react-native-modular
Steps:
same issue as @remisaado. Using @Guihgo 's example will result in a new render for each time you switch between screens. For example going A->B = B renders once A - B - A - B = B rendering twice A - B - A - B - A - B = B rendering thrice
and so on. Setting the navigation key therefore is not very effective. Spent the afternoon trying to circumvent the multiple renders and couldnt find anythin
no solutions worked for me... this is very frustrating
stack1: a-b-c stack2: d-e-f
navigate() from f to c and goBack() on c => a
@mi-mazouz did you find any solution for this bug ?
@Twinski I definitely had to put it in another stack or at the top of the main stack
I had same problem. After doing quite a lot of research, I still couldn't find any clean & elegant solution that I could deeply understand.
So I ended up putting multiple "steps" into one single screen, so goBack() from any step of this single screen would exit the entire flow.
The implementation is actually not too bad, as I could 100% understand what's going on there and structure the code in a maintainable way :)
I'm new to react native but i hope this helps. I have found a way to navigate to a parent container from it's child using navigation.navigate() function. You have to replace navigation.goBack
property received from parent component with navigation.goBack = () => navigation.navigate('YourNotNestedRoute');
...
Until recently, we had navigation.goBack(null)
, for navigating out of nested stackNavigator. Because navigation.goBack()
just showed us blank screen. But we noticed, isFocused
listener stopped working whenever we called navigation.goBack(null)
. Actually all listeners stopped working ('willBlur', 'didFocus',....) - but I'm not sure that is the cause.
So this is what I found out:
mode: 'modal',
and you navigate to nested StackNavigator, you need to call navigation.pop()
when you want to exit the nested StackNavigator.navigation.goBack()
mode: modal
StackNavigator, you will see the blank screen.navigation.goBack(null)
, does it remove navigation listenres?I hope this helps.
Thank you @LeDanielH , navigation.pop() helped me escape a drawer navigation that would not let me return to the other navigators I had.
Hey everyone! š I've been trying a lot of things but nothing worked out so far.. š¤
I can navigate to InsuranceAddNavigator without a problem. In InsuranceAddNavigator (which is used to go through 5 steps > Next > Next > Next ...) I'd like to be able to dismiss the whole InsuranceAddNavigator-flow from any screen inside it (eg. Teaser, Quote, Terms, ..).
I've tried to call this.props.navigation.dispatch({ type:'Navigate/BACK', routeName:null }); Cause my modalNavigator has no routeName, correct? How can I say to my ModalNavigator: quit the InsuranceAdd-flow?