-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
createMaterialBottomTabNavigator isn't working with expo-router and nested navigation #4496
Comments
@flyingL123 This reads as though it is a react-navigation or expo-router issue regarding navigation. What leads you to think it is a react-native-paper issue? If there's no clear indication that it is related to RNP, please close this issue. |
@gregfenton If you watch the video or follow the steps I outlined, you will see there is only a bug when the Material Bottom Tabs Navigator is used. Simply swapping out Material Bottom Tabs Navigator and using the default tabs instead, the bug goes away. So I assumed the issue has to be related to Material Bottom Tabs Navigator. I really don't know enough to offer more than that, but I think I pretty clearly isolated the issue down to Material Bottom Tabs Navigator. |
Okay thanks for the clarification. I see it now. Not too surprising that this has issues. RNP is wrapping functionality from React-Navigation, and Expo-Router is wrapping React-Navigation. So trying to get RNP to work with Expo-Router is going to be a confusing mess. My suspicion is that the "right fix" for this is to simply document "if you want bottom buttons with Expo-Router, use its bottom buttons and not RNP's" ? |
I guess if it’s really that difficult to make it work, then yea, but the RNP tabs are really nice. Especially the little animation when the highlighted tab changes. I must have spent 2 days trying to get it to work before giving up and just using the default tabs. That’s how much better I liked the RNP ones :) |
I really wanted this to work, so I looked at what expo-router does and came up with this simple but working solution:
Then you can use MaterialTabs as you would use expo-router tabs:
And can put your Shall I submit a doc PR? |
In order to use the import { Tabs } from "expo-router";
import { CommonActions } from "@react-navigation/core";
import { PropsWithChildren } from "react";
import { BottomNavigation, BottomNavigationProps } from "react-native-paper";
export type MaterialBottomTabsProps = PropsWithChildren<
Omit<
BottomNavigationProps<any>,
| "navigationState"
| "safeAreaInsets"
| "onTabPress"
| "renderIcon"
| "getLabelText"
| "onIndexChange"
| "renderScene"
>
>;
export function MaterialBottomTabs({
children,
...props
}: MaterialBottomTabsProps) {
return (
<Tabs
screenOptions={{
headerShown: false,
}}
tabBar={({ navigation, state, descriptors, insets }) => (
<BottomNavigation.Bar
{...props}
navigationState={state}
safeAreaInsets={insets}
onTabPress={({ route, preventDefault }) => {
const event = navigation.emit({
type: "tabPress",
target: route.key,
canPreventDefault: true,
});
if (event.defaultPrevented) {
preventDefault();
} else {
navigation.dispatch({
...CommonActions.navigate(route.name, route.params),
target: state.key,
});
}
}}
renderIcon={({ route, focused, color }) => {
const { options } = descriptors[route.key];
if (options.tabBarIcon) {
return options.tabBarIcon({ focused, color, size: 24 });
}
return null;
}}
getLabelText={({ route }) => {
const { options } = descriptors[route.key];
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel
: options.title !== undefined
? options.title
: "title" in route
? route.title
: route.name;
return String(label);
}}
/>
)}
>
{children}
</Tabs>
);
}
MaterialBottomTabs.Screen = Tabs.Screen; You can then use import { MaterialBottomTabs as Tabs } from "[...]";
// ...
<Tabs
activeIndicatorStyle={{ backgroundColor: routeColor }}
barStyle={{
alignContent: "center",
backgroundColor,
elevation: 2,
zIndex: 2,
}}
compact
shifting
sceneAnimationEnabled={false}
activeColor={activeColor}
inactiveColor={inactiveColor}
>
<Tabs.Screen
name="Home"
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color, size }) => {
return <Icon name="home" size={size} color={color} />;
},
}}
href="[...]"
/>
<Tabs.Screen
name="Settings"
options={{
tabBarLabel: 'Settings',
tabBarIcon: ({ color, size }) => {
return <Icon name="cog" size={size} color={color} />;
},
}}
href="[...]"
/>
</Tabs> |
@SleeplessByte Might need a few adjustments to support |
As in use the integrated react router appbar? I never use that hence the header shown false 🤝😁 |
I tried it and it works to a degree. The only thing i couldn't manage to get working was respecting the TabBar labels in the header. So nothing too bad 😄 |
Ah yeah sorry, I don't use that Header. Always mount it myself in the screen ;) |
You need to add at least one child (a tab). |
It looks like you're not importing import { MaterialBottomTabs as Tabs } from "[...]"; This should replace whatever other |
That looks right. Can you update the file you import to: export type MaterialBottomTabsProps = PropsWithChildren<
Omit<
BottomNavigationProps<any>,
| "navigationState"
| "safeAreaInsets"
| "onTabPress"
| "renderIcon"
| "getLabelText"
| "onIndexChange"
| "renderScene"
>
>;
export function MaterialBottomTabs({
children,
...props
}: MaterialBottomTabsProps) {
// ...same as before The props excluded are being set by the component, so the type, indeed, was not correct. |
I cannot reproduce that, as Perhaps a different version or tsconfig mismatch. However, you can safely export type MaterialBottomTabsProps = PropsWithChildren<
Omit<
BottomNavigationProps<any>,
| "navigationState"
| "safeAreaInsets"
| "onTabPress"
| "renderIcon"
| "getLabelText"
| "onIndexChange"
| "renderScene"
| "children" // <-- this
>
>; That should not do anything because: Alternatively you can not use export type MaterialBottomTabsProps = Omit<
BottomNavigationProps<any>,
| "navigationState"
| "safeAreaInsets"
| "onTabPress"
| "renderIcon"
| "getLabelText"
| "onIndexChange"
| "renderScene"
> & { children?: React.ReactNode | undefined } If that works, then the issue is with the Finally, as you need to return <Tabs
children={[
<Tabs.Screen
name="Home"
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color, size }) => {
return <Icon name="home" size={size} color={color} />;
},
}}
href="[...]"
/>
<Tabs.Screen
name="Settings"
options={{
tabBarLabel: 'Settings',
tabBarIcon: ({ color, size }) => {
return <Icon name="cog" size={size} color={color} />;
},
}}
href="[...]"
/>
</Tabs>]} /> Or if it doesn't take an Array for you, wrap it in |
Thank you very much for your help. I have tried all those solutions and they all work. It's enough to get me going, very much appreciate it. Just a heads up, I do get this warning if you have time, otherwise thank you very much for your time again!
|
There's two PR open to address that. One of them has a patch package fix you can apply today: #4494 (comment) |
Current behaviour
I am attempting to nest a stack navigator inside one of the tabs of a Material Bottom Tab Navigator in a project that uses expo-router. Navigating between tabs works as expected, but, on the third tab I created a nested stack navigator. The tab contains a link to "Go to another page", which links to the next screen in the stack. However, when I click the link, no navigation takes place. On web, I see the URL does change as expected, but the screen does not change.
When I comment out my the material tab navigator, and instead use the built-in Tabs from expo-router, now the stack navigation inside the third tab works as expected.
Expected behaviour
I expect the stack navigation in tab 3 to work properly using createMaterialBottomTabNavigator.
How to reproduce?
I created this repo using the command
npx create-expo-app@latest --template tabs
https://github.com/flyingL123/expo-nav-test
I made a few minor adjustments to the app that was created in order to add a 3rd tab with a nested stack navigator.
To reproduce the problem, you just need to clone that repo, install dependencies, and run the app with
npx expo start
. View the app, click on tab 2, click on tab 3. Tab navigation works as expected. While on tab 3, click the link that says "Go to another page". The stack navigator will take you to the page.Now, open file
app/(tabs)/_layout.tsx
. Comment out lines 28-71 (the Tabs element). Then uncomment lines 73-96, in order to use the Material Tabs instead.Reload the app, click on tab 2, click on tab 3. That all still works. However, click on the "Go to another page" link, and you will not navigate as expected. This is the bug. I think there may be an issue with the Material Bottom Tabs Navigator and expo-router having to do with stack navigators nested in the tabs.
Preview
Here is a screen recording of me doing the steps above to demonstrate the issue:
https://youtu.be/Hsbf8CT1RQg
What have you tried so far?
I have been searching for documentation, watching video clips, trying to find my own workarounds. I can't get it to work so I am wondering if there may be an issue with the library.
Your Environment
The text was updated successfully, but these errors were encountered: