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

[Expo 43] Blank screen when native stack is nested inside material bottom tabs #1197

Closed
2 of 7 tasks
Gruak opened this issue Oct 31, 2021 · 15 comments
Closed
2 of 7 tasks

Comments

@Gruak
Copy link

Gruak commented Oct 31, 2021

Description

Using recently released expo 43, when native stacks are nested inside material bottom tabs navigator (react-navigation), navigating between tabs back and forth causes a blank screen to appear.
The identical navigation setup works fine in expo 42.
This is a repost of this issue: react-navigation/react-navigation#10081

Demo

screen-20211026-181850.mp4

Steps To Reproduce

  1. Use material bottom tabs navigator (@react-navigation/material-bottom-tabs)
  2. Nest two (or more) native stack navigators (@react-navigation/native-stack) inside material bottom tabs navigator
  3. Navigate between tabs back and forth

Expected behavior

I expect the screen content to be properly displayed when navigating, as it is in case of using @react-navigation/bottom-tabs (not material) and/or @react-navigation/stack (not native) or how it used to be in expo 42.

Actual behavior

Navigating between tabs back and forth causes a blank screen to appear.

Reproduction

https://github.com/Gruak/react-navigation-material-bottom-tabs-bug-repro

Platform

  • iOS
  • Android
  • Web
  • Windows
  • tvOS

Workflow

  • Managed workflow
  • Bare workflow

Package versions

package version
react-native 0.64.2
@react-navigation/native 6.0.6
@react-navigation/native-stack 6.2.5
@react-navigation/material-bottom-tabs 6.0.9
react-native-screens 3.8.0
react-native-safe-area-context 3.3.2
expo 43.0.1
@ferrannp
Copy link
Contributor

ferrannp commented Nov 8, 2021

I have exactly the same issue (without expo) with all libraries to latest and react-native@0.64.2.

@jordann93
Copy link

Same here since Expo 43

@WoLewicki
Copy link
Member

WoLewicki commented Nov 29, 2021

I believe it comes from the fact that material-bottom-tabs uses Android Fragment library, same as other navigators with react-native-screens enabled. This commit: #1066 added new behavior of Fragments in our library, and it must have introduced some problems with integration with material-bottom-tabs (it is not true apparently since material-bottom-tabs does not use Fragments). In the issue in react-navigation, I can see that someone said it has already been fixed: react-navigation/react-navigation#10081 (comment). Can you check if it is true, and, if so, can I close this issue?

@Gruak
Copy link
Author

Gruak commented Nov 30, 2021

@WoLewicki I did check and unfortunately after applying the suggested solution the issue still occurs.

@WoLewicki
Copy link
Member

This issue comes from the usage of removeClippedSubviews in material-bottom-tabs, which removes the views on native side when switching tabs while not removing them on React side. It brings messy behavior and destroys the react-native-screens logic. A workaround is to not use this in material-bottom-tabs by e.g. changing the code here: https://github.com/callstack/react-native-paper/blob/main/src/components/BottomNavigation.tsx#L631 to:
Platform.OS === 'ios' ? navigationState.index !== index : false. Can you check if it resolves the issue?

@Gruak
Copy link
Author

Gruak commented Dec 3, 2021

A workaround is to not use this in material-bottom-tabs by e.g. changing the code here: https://github.com/callstack/react-native-paper/blob/main/src/components/BottomNavigation.tsx#L631 to: Platform.OS === 'ios' ? navigationState.index !== index : false. Can you check if it resolves the issue?

You were right! That sorts it out.

@WoLewicki
Copy link
Member

I found even simpler solution with no need of changes in the code of library. When you nest the native-stack inside the tab of material-bottom-tabs, add another View with collapsable={false} before providing the navigator, something like this:

const TabOneStack = createNativeStackNavigator();

function TabOneNavigator() {
  return (
    <View style={{flex: 1}} collapsable={false}>
      <TabOneStack.Navigator>
        <TabOneStack.Screen
          name="TabOneScreen"
          component={TabOneScreen}
          options={{ headerShown: false }}
        />
      </TabOneStack.Navigator>
    </View>
  );
}

const BottomTab = createMaterialBottomTabNavigator();

function BottomTabNavigator() {

  return (
    <BottomTab.Navigator initialRouteName="TabOne">
      <BottomTab.Screen
        name="TabOne"
        component={TabOneNavigator}
      />
    </BottomTab.Navigator>
  );
}

It should prevent the issues with logic of native layouts of react-native-screens and removeClippedSubviews of material-bottom-tabs. Can you check if it works? If so, can we close this issue?

@kendallroth
Copy link

While I can confirm that the above does work (using an extra View with collapsable set to false), that is still a workaround and should not be accepted as a fix (although I thank you immensely for discovering this!). Even simply patching the react-native-screens use of removeClippedSubviews for Android does not seem like the ideal/final fix 🤷.

@WoLewicki
Copy link
Member

@kendallroth does this issue exist in newer versions of react-native in your case? Expo uses RN 0.64.3, but from my testing it seems that on e.g. 0.66.3 it works correctly without any fixes. Could you check it too?

@kendallroth
Copy link

@WoLewicki Good question, I thought about waiting until Expo SDK 44 comes out, but that is also using RN 0.64.3 so no luck there. I was able to use the above workaround (the collapsable one) and may test the other one later. I may see if I can test this out later (typically only work with Expo), as it's good to hear that it might be fixed in later versions of react-native? Was the issue with that instead of react-native-screens (seems odd based on above comments/fixes)?

@WoLewicki
Copy link
Member

The issue comes from the way the layout system works in react-native when using removeClippedSubviews and its integration with react-native-screens. I am not sure what was changed exactly between the versions, maybe it is fixed due to fact of newer version of appCompat used by newer versions of react-native, but I am not sure and I have already spent much time debugging it. Since introducing additional View with collapsable set to false should not introduce any performance problems and the issue is not present in newer versions, I think this issue can be closed, or am I not seeing something?

@Gruak
Copy link
Author

Gruak commented Dec 20, 2021

I tested it with react-native 0.65.0 and the issue does not occur. I suppose it was fixed due to the following commit facebook/react-native@da8ed6b. @WoLewicki I think the solution you proposed is good enough, so we can wait until expo bumps RN version. I guess the issue can be closed, thank you all for your time.

@kendallroth
Copy link

@WoLewicki Yes, I completely agree, if it appears fixed in newer versions than adding an additional View in older versions is acceptable 👍. I did not have time over the weekened to experiment with this, but am not super worried either since someone else has validated it as well.

@WoLewicki
Copy link
Member

Ok, I am closing it then. Thanks for your contribution 🎉

@gabpaet
Copy link

gabpaet commented Nov 9, 2022

I am still experiencing the issue even though I already did the workaround. My react-native version is 0.67.5 and I'm on the latest version of react-navigation and react-native-screens, The initial tab is not rendering correctly when opening the app but the second tab is rendering okay.

Here's my code:

const Tab = createMaterialBottomTabNavigator();
const Stack = createNativeStackNavigator();

const headerBackgroundColor =
	ENVIRONMENT === 'development' || ENVIRONMENT === 'sandbox'
		? '#FFA500'
		: ENVIRONMENT === 'preprod'
		? '#177302'
		: '#023348';

const headerTitleColor = ENVIRONMENT === 'preprod' || ENVIRONMENT === 'production' ? '#fff' : '#000';

const BookmarkStackScreen = () => {
	return (
		<View collapsable={false} style={{ flex: 1 }}>
			<Stack.Navigator>
				<Stack.Screen
					component={BookmarkScreen}
					name="BookmarkStack"
					options={{
						headerShown: true,
						headerStyle: { backgroundColor: headerBackgroundColor },
						headerTitle: 'Menu',
						headerTitleAlign: 'center',
						headerTitleStyle: { color: headerTitleColor, fontSize: 20 }
					}}
				/>
			</Stack.Navigator>
		</View>
	);
};

const AccountStackScreen = () => {
	return (
		<View collapsable={false} style={{ flex: 1 }}>
			<Stack.Navigator>
				<Stack.Screen
					component={AccountScreen}
					name="AccountStack"
					options={{
						headerShown: true,
						headerStyle: { backgroundColor: headerBackgroundColor },
						headerTitle: 'My Account',
						headerTitleAlign: 'center',
						headerTitleStyle: { color: headerTitleColor, fontSize: 20 }
					}}
				/>
			</Stack.Navigator>
		</View>
	);
};

const App = () => {
	return (
		<NavigationContainer>
			<Tab.Navigator
				activeColor="#143444"
				barStyle={{ backgroundColor: '#fff', elevation: 10 }}
				initialRouteName="BookmarkTab">
				<Tab.Screen
					component={BookmarkStackScreen}
					name="BookmarkTab"
					options={{
						tabBarIcon: ({ color }) => <FontAwesome5 color={color} name="bookmark" size={20} solid />,
						tabBarLabel: 'Menu'
					}}
				/>
				<Tab.Screen
					component={AccountStackScreen}
					name="AccountTab"
					options={{
						tabBarIcon: ({ color }) => <FontAwesome5 color={color} name="user-circle" size={20} solid />,
						tabBarLabel: 'My Account'
					}}
				/>
			</Tab.Navigator>
		</NavigationContainer>
	);
};

export default App;

Here are the screenshots of the first and second tabs:

1667977422924
1667977422900

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

6 participants