Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v5] Navigation glitch after first entering stack #6651

Closed
ewnavilae opened this issue Dec 5, 2019 · 8 comments
Closed

[v5] Navigation glitch after first entering stack #6651

ewnavilae opened this issue Dec 5, 2019 · 8 comments

Comments

@ewnavilae
Copy link

Sorry for not using the template but it wouldn't make sense to do so in this case as the problem is pretty clear and easy to reproduce. I also apologize if I lack politeness or coherence as I have been trying to workaround this bug for an enormous amount of time and it has frustrated me deeply.

I am using "next" version for everything.

TL;DR first: After navigating to any screen inside a stack, subsequent navigations to screens inside that stack first push the initial screen and only then the newly navigated-to screen.

I have a simple navigation setup where I use a <Stack.Navigator> that handles authentication flow, then an Application stack using MaterialBottomTabsNavigator inside of which I have all of my application's screens.
One of these screens is a Stack.Navigator called More and here is where the issue is happening:
Whenever I navigate inside a screen of this Stack, using navigation.navigate( "More", { screen: "ExampleScreen" } ), there is no problem the first time, but every other navigate call I make to a screen inside More first renders the first More screen loaded, then the screen I actually navigated to, making it so if I go back it returns to that screen first instead of the screen I was in.

Example of the described behaviour:

  1. Open application, loading home screen
  2. Open menu and click Settings ( ApplicationStack -> MoreStack -> Settings )
  3. The settings screen is loaded
  4. Pressing back returns the application to home screen
  5. Open menu and click Reviews ( ApplicationStack -> MoreStack -> Reviews )
  6. The settings screen (first loaded) is briefly visible and Reviews screen appears in front of it.
  7. Pressing back returns to the settings screen, have to press back again to return to the home screen

I am only using @react-navigation/stack stacks and a single @react-navigation/material-bottom-tabs stack, therefore my structure is:

<Tabs.Navigator>
<Tabs.Screen name="Schedule" />
<Tabs.Screen name="Clients" />
<Tabs.Screen name="Pets" />
<Tabs.Screen name="Notifications" />
<Tabs.Screen name="More"  /* this is the problematic stack */>
</Tabs.Navigator>

I have tried everything to work around this bug such as navigation differently (with dispatch, with resetRoot), attempting to clear the history for the More stack, etc. and everything simply resulted in more unexpected behaviour.

You can see a gif of the situation described:
ezgif-4-67efd73809e8

Does this problem make sense to anyone? I wanted to see if maybe someone else has experienced this or anyone has an idea of what it could be before I go and spend additional time in creating a test repo.

@ewnavilae ewnavilae changed the title [v5] Navigation glitch after first enterting stack [v5] Navigation glitch after first entering stack Dec 5, 2019
@satya164 satya164 transferred this issue from react-navigation/react-navigation Jan 4, 2020
@satya164
Copy link
Member

satya164 commented Jan 4, 2020

Please provide repro code

@ewnavilae
Copy link
Author

ewnavilae commented Jan 6, 2020

Hello Satyajit,

I have created a minimal repository to reproduce the issue at hand.

https://github.com/ewnavilae/rnnavbug

There is a small patch (although it looks like it changes a lot of things because I saved the formatting) that allows custom onTabPress in order to open a menu when tab 4 is pressed.

The setup I use with this repository is as follows:

git clone git@github.com:ewnavilae/rnnavbug.git;
cd rnnavbug;
yarn;
yarn patch-package;
cd android && ./gradlew installDebug; cd ..;
adb reverse tcp:8081 tcp:8081;
yarn start;

Afterwards, the intended behaviour when using the application is:

  1. Open menu by pressing tab 4
  2. Navigate to screen 0
  3. Press back button returning to tab 0
  4. Open menu by pressing tab 4
  5. Navigate to screen 1
  6. Press back button returning to tab 0

The observed behaviour is:

  1. Open menu by pressing tab 4
  2. Navigate to screen 0
  3. Press back button returning to tab 0
  4. Open menu by pressing tab 4
  5. Navigate to screen 1
  6. Press back button returning to screen 0
  7. Press back button returning to tab 0

It appears as though the history in the "More" stack is being preserved despite going back in step 3.

I still believe I could be doing something wrong, so thank you for your response and taking the time to analyze this issue.

@satya164
Copy link
Member

satya164 commented Jan 6, 2020

Can you update to the latest alpha please? You're on an old version.

@ewnavilae
Copy link
Author

ewnavilae commented Jan 6, 2020

Satyajit,

I had tried updating the packages for the last month since I posted the issue and I have updated the repository to the latest version and the problem still persists.

I used the following command to update:
yarn add @react-navigation/bottom-tabs@next @react-navigation/core@next @react-navigation/material-bottom-tabs@next @react-navigation/material-top-tabs@next @react-navigation/native@next @react-navigation/native-stack@next @react-navigation/stack@next

Current versions:

"@react-navigation/core": "^5.0.0-alpha.30",
"@react-navigation/material-bottom-tabs": "^5.0.0-alpha.29",
"@react-navigation/material-top-tabs": "^5.0.0-alpha.27",
"@react-navigation/native": "^5.0.0-alpha.22",
"@react-navigation/native-stack": "^5.0.0-alpha.22",
"@react-navigation/stack": "^5.0.0-alpha.54",

Can you confirm the issue occurs as described?

Thank you

@satya164
Copy link
Member

satya164 commented Jan 6, 2020

Open menu by pressing tab 4

I ran the example you provided both on iOS and Android, but pressing tab 4 doesn't open any menu.

It appears as though the history in the "More" stack is being preserved despite going back in step 3.

Going to a different tab doesn't unmount previous tabs. This is the expected behaviour and it was the same in React Navigation 4.

I presume the "glitch" you're describing is just the screen transition animation of the stack. From the behaviour you are describing that you want, sounds like you don't want it to behave like a stack (no stack history, no animation etc.).

Since you don't want the behaviour of stack, I'd suggest that instead of rendering a stack, render a normal component, pass what you want to render as params and return the component appropriately:

function MoreScreen(route) {
  switch(route.params?.screen) {
    case 'Settings':
      return <Settings />;
    case 'Dashboard'
      return <Dashboard />;
  }
}

// ...

navigation.navigate('More', { screen: 'Settings' });

@satya164 satya164 closed this as completed Jan 6, 2020
@ewnavilae
Copy link
Author

ewnavilae commented Jan 6, 2020

Are you saying if a tab contains a stack navigator, I navigate into a screen inside that stack, then navigate back, the next time I navigate into a screen inside that stack the first screen I visited should still be in the history? I can't understand the rationale behind back. Aren't screens removed from history every time you go back?

Also, did you clone the repo using the list of commands I provided or apply the patches using yarn patch-package? It is necessary for the menu to work.

Your solution would work for this example but not for my application because it has more complex navigation inside the MoreStack, this simplified example was only intended to show the bug.

Here is what happens when you install the app and follow the steps I provided:
bug

@satya164
Copy link
Member

satya164 commented Jan 6, 2020

I can't understand the rationale behind back. Aren't screens removed from history every time you go back?

Screens are removed from history, but they aren't unmounted in tab navigator or drawer navigator. Tab navigator doesn't behave the same as stack.

Your solution would work for this example but not for my application because it has more complex navigation inside the MoreStack, this simplified example was only intended to show the bug.

You'll need to adapt it to fit your app. You can't use Stack because the the behavior you want isn't how Stack Navigator behaves. The behavior you want is more like how tab navigator behaves with backBehavior: "none". So if you want to keep the same structure then you can build a custom tab navigator that just renders the focused screen (https://reactnavigation.org/docs/en/next/custom-navigators.html ) and use it instead of stack navigator.

Also, did you clone the repo using the list of commands I provided or apply the patches using yarn patch-package? It is necessary for the menu to work.

I missed patch package (you should add it to postinstall instead of another command). But anyway, the behavior is the expected behavior and is the same as previous versions of React Navigation. This is not a bug.

@ewnavilae
Copy link
Author

I missed patch package (you should add it to postinstall instead of another command). But anyway, the behavior is the expected behavior and is the same as previous versions of React Navigation. This is not a bug.

That's right, sorry, I was in a rush to get the repro ready as this is a long standing issue that could block the release of the application I'm working on!

So if I got it correctly, the first screen I ever access in that stack is there simply because when I go back to another tab, the stack is not unmounted?
Even if that's not exactly it, I think I finally understand that my confusion derives from a misunderstanding of how a stack navigator behaves.

I have managed to work around this problem by applying the following code in the MoreStack navigator:

useEffect( () => {
  navigation.addListener( "blur", () => {
    setMounted( false )
  } )
  navigation.addListener( "focus", () => {
    setMounted( true )
  } )
}, [] )

And by returning null when mounted is false.
This way, whenever I "leave" the more stack it gets reset, as is intended.

I think maybe a switch navigator would be more appropriate for my use case, is it being removed in the 5.0 version?

Thank you very much for helping me clear up this issue.

@satya164 satya164 transferred this issue from react-navigation/navigation-ex Feb 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants