react-native : stack navigation into tab navigation whitout showing it - react-native

So i have a bottom tab navigation into app.js with 3 tabs:
=> map
=> user
=> settings
<NavigationContainer>
<TabNav.Navigator initialRouteName='home'>
<TabNav.Screen name='home' component={Map} options={{
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="map-search-outline" color={color} size={30} style={style.iconStyle} />
), tabBarLabel: (null)
}} />
<TabNav.Screen name='user' component={User} options={{
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="card-account-details-outline" color={color} size={30} style={style.iconStyle} />
),tabBarLabel: (null)
}} />
<TabNav.Screen name='settings' component={Settings} options={{
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="set-square" color={color} size={30} style={style.iconStyle} />
), tabBarLabel: (null)
}} />
</TabNav.Navigator>
</NavigationContainer>
So I want to acces to a stack nav screen (report for exemple) anywhere into the children screens/components (a modal for exemple) of the map or the settings but not from the homescreen without showing it in the nav of the homescreen or the direct child of this homescreen, how can I do ?
In other words, I think I dont know where to write my hidden stack nav to be accessible from everywhere in the app. (but I understand how to pass it with the props)

Related

Passing props to Tab.Screen within BottomTabNavigator

I am running into difficulty passing props to one of my TabScreens using react-native's BottomTabNavigator. I have tried a couple of different options. Without props the Tab.Screen looks like this:
<Tab.Screen
name='Visits'
component={VisitsTab}
options={{
tabBarLabel: 'Visits',
tabBarIcon: ({ color, size }) => <FontAwesome name='street-view' color={color} size={size} />,
}}
/>
So what I tried was this:
<Tab.Screen
name='Visits'
component={(props) => <VisitsTab {...props} />}
options={{
tabBarLabel: 'Visits',
tabBarIcon: ({ color, size }) => <FontAwesome name='street-view' color={color} size={size} />,
}}
/>
This still doesn't work, as the prop I am logging out in the VisitsTab is undefined - in other words, the VisitsTab is not receiving props. And to clarify, props is available in the MainScreen that passed on the props. What am I missing here?
By the way, I also tried this, but get the same issue:
<Tab.Screen
name='Visits'
options={{
tabBarLabel: 'Visits',
tabBarIcon: ({ color, size }) => <FontAwesome name='street-view' color={color} size={size} />,
}}
>
{(props) => <VisitsTab {...props} />}
</Tab.Screen>
The full navigation for this bottom tab navigator looks like this:
import { VisitsTab } from './tabs/VisitsTab';
import { ChartTab } from './tabs/ChartTab';
import { GoalsTab } from './tabs/GoalsTab';
export const MainScreen = (props) => {
const Tab = createBottomTabNavigator();
return (
<Tab.Navigator
screenOptions={{
headerShown: true,
title: 'Patient',
headerLeft: () => (
<Feather
name='chevron-left'
size={24}
onPress={() => props.navigation.goBack()}
/>
),
}}
initialRouteName={'Visits'}
>
<Tab.Screen
name='Visits'
component={(props) => <VisitsTab {...props} />}
options={{
tabBarLabel: 'Visits',
tabBarIcon: ({ color, size }) => <FontAwesome name='street-view' color={color} size={size} />,
}}
/>
<Tab.Screen
name='Chart'
component={ChartTab}
options={{
tabBarLabel: 'Charts',
tabBarIcon: ({ color, size }) => <FontAwesome name='id-badge' color={color} size={size} />,
}}
/>
<Tab.Screen
name='Goals'
component={GoalsTab}
options={{
tabBarLabel: 'Edit Goals',
tabBarIcon: ({ color, size }) => <FontAwesome name='trophy' color={color} size={size} />,
}}
/>
</Tab.Navigator>
);
};
By the way, somewhat frustratingly, the documentation page for the Bottom Tabs Navigator doesn't actually address how to pass props.
Props for a component (for a screen to be precise) are not passed by the navigation framework. Props are passed from a parent to its child components. When writing component={Visits}, we do not instantiate an actual JSX components. Thus, there are no props to be passed.
In order to pass information during navigation, we use the route params. Here is an example: navigation.navigate("Visits", {x: 42}).
However, if Visits is supposed to be an initial screen of some navigator, then we have never actually navigated. Thus, the above approach does not help.
For this reason, the react-navigation framework added the initialParams prop for screens. They are defined inside the screen of some navigator.
<Tab.Screen
name='Visits'
component={VisitsTab}
initialParams={props}
/>
whereby props is any object and it might be better to use a different name, since these aren't actual props.
Then, access them in your screen.
function VisitsTab({route}) {
const params = route?.params
return (...)
}
We can access the passed information via params.

React navigation initialRouteName property not working as expected

In my react native app I nested stack navigation inside the tab navigation.
I can't access the screen that I set as an initial route in stack navigation.
The tab navigation component is
<Tab.Navigator initialRouteName='HomeNav' >
<Tab.Screen name="HomeNav" component={HomeNav}
options={{
tabBarIcon: ({ color, size }) => (
<FIcon name="home" color={color} size={size} />
),
}}
/>
<Tab.Screen name="Search" component={Search}
options={{
tabBarIcon: ({ color, size }) => (
<FIcon name="search" color={color} size={size} />
)
}}
/>
<Tab.Screen name="Cart" component={Cart}
options={{
tabBarIcon: ({ color, size }) => (
<MCIcon2 name="cart" color={color} size={size} />
)
}}
/>
<Tab.Screen name="AccountNav" component={AccountNav}
options={{
tabBarIcon: ({ color, size }) => (
<MCIcon2 name="account" color={color} size={size} />
)
}}
/>
</Tab.Navigator >
And here is the account navigation component
const AccountNav = () => {
return (
<Stack.Navigator
initialRouteName="Account"
screenOptions={{
headerShown: false
}}
>
<Stack.Screen name="Account" component={Account} />
<Stack.Screen name="MyOrders" component={MyOrders} />
<Stack.Screen name="Profile" component={Profile} />
</Stack.Navigator>
);
when I try to navigate to MyOrders screen from the other screens. it gets stuck and cannot access the initial route screen (Account).
I had this issue aswell, I solved it by adding lazy: false to the tab navigators screenOptions prop.
screenOptions={{
headerShown: false,
lazy: false
}}
Documentation says that "Routes are lazily initialized -- their screen components are not mounted until they are first focused.", my guess is that the initial route you specify won't "register" until the screen's components are properly mounted (until the screen is focused), so when you go to your AccountNav, the initial route becomes the one you navigated too, bypassing the prop.
The issue with this is that you're mounting all the screen components from all the screens and that may impact performance depending on your application I guess

React Native Tab Navigator

I am totally new to React Native and I am currently trying show BottomTabNavigator on child/details page, for example:
I have a page called Training and I have another page called TrainingDetails.
I wanna show BottomTabNavigator on TrainingDetails.
On truth, I wanna show BottomTabNavigator in all pages, main pages and detail pages.
Here is my Main.js
Thanks so much!
const Tab = createBottomTabNavigator();
return (
<Tab.Navigator tabBarOptions={{ activeTintColor: theme.colors.primary, inactiveTintColor: theme.colors.neutral_100, style: {backgroundColor: theme.colors.active} }}>
<Tab.Screen
options={{
title: "Trabalhar",
tabBarIcon: ({ focused, color, size }) => (
<MaterialIcon name={"headset"} size={size} color={color} />
),
}}
name="Home"
component={HomeScreen}
/>
<Tab.Screen
options={{
title: "Estudar",
tabBarIcon: ({ focused, color, size }) => (
<SimpleLineIcon name={"graduation"} size={size} color={color} />
),
}}
name="Study"
component={Training}
/>
<Tab.Screen
options={{
title: "Notificações",
tabBarIcon: ({ focused, color, size }) => (
<MaterialIcon name={"bell-outline"} size={size} color={color} />
),
}}
name="Notification"
component={HomeScreen}
/>
<Tab.Screen
options={{
title: "Resultados",
tabBarIcon: ({ focused, color, size }) => (
<MaterialIcon name={"trending-up"} size={size} color={color} />
),
}}
name="Results"
component={HomeScreen}
/>
<Tab.Screen
options={{
title: "Carteira",
tabBarIcon: ({ focused, color, size }) => (
<MaterialIcon name={"wallet-outline"} size={size} color={color} />
),
}}
name="Wallet"
component={HomeScreen}
/>
</Tab.Navigator>
);
};
export default Main;
You can put a stackNavigator inside a tab navigator, so for example if you want a home screen and then another screen called details that doesn't have a tab at the bottom but still has the tabs at the bottom you can replace the home screen with a homeStack that has both a home screen and details screen inside it.
const Stack = createStackNavigator();
function HomeStack() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Details" component={Details} />
</Stack.Navigator>
);
}
and then replace your home component in the tab navigator with HomeStack component.

ReactNative: Using Drawer.Navigator inside TabNavigator throws "navigation.openDrawer is not a function"

What I want to achive:
Tap on an icon in bottomTabNavigator to open DrawerNavigator.
What I get:
An error stating: "TypeError: navigation.openDrawer is not a function. (In 'navigation.openDrawer()', 'navigation.openDrawer' is undefined)"
My Code:
<NavigationContainer>
<Tab.Navigator
initialRouteName="Home"
tabBarOptions={{
activeTintColor: '#e91e63',
style: {},
labelStyle: {margin:0},
}}
>
<Tab.Screen
name="Home"
component={HomeStack}
options={{
tabBarLabel: 'News',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="newspaper" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="Categories"
component={CategorieStack}
options={{
tabBarLabel: 'Kategorien',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="format-list-bulleted-square" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="Menu"
component={DrawerStack}
options={{
tabBarLabel: 'Menu',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="menu" color={color} size={size} />
),
}}
listeners={({ navigation }) => ({
tabPress: e => {
e.preventDefault();
navigation.openDrawer();
}
})}
/>
</Tab.Navigator>
</NavigationContainer>
and
const Drawer = createDrawerNavigator();
function DrawerStack() {
return (
<Drawer.Navigator>
<Drawer.Screen name="Home" component={Home} />
<Drawer.Screen name="Categories" component={Categories} />
</Drawer.Navigator>
);
}
Already read:
https://github.com/react-navigation/hooks/issues/36
Opening the Drawer navigator from the bottom tab
And many more. Just can't seem to get it to work. I think I do miss a really important point in this. Is anyone able to point me into the right direction?
In my case, my bottomTabNavigator is a child of my drawerNavigator( not sure if this is required for it to work tho)
so using this bit works:
listeners={({ navigation }) => ({
tabPress: e => {
e.preventDefault();
navigation.openDrawer();
}
})}
Inside Drawer Navigator:
<Drawer.Navigator
initialRouteName="MyRoute"
drawerStyle={styles.drawerStyle}
lazy
>
{/*Bottom Tab Navigator*/}
<Drawer.Screen
name="MyRoute"
component={MyBottomTabs}
options={{
drawerIcon: ({ focused, size }) => (
<Ionicons
name={focused?"md-home": "md-home-outline"}
size={size}
color={focused ? COLORS.primary : '#ccc'} />
)
}}
/>
<Drawer.Screen
name="Profile"
component={UserProfile}
options={{
drawerIcon: ({ focused, size }) => (
<Ionicons
name={focused?"md-person-sharp": "md-person-outline"}
size={size}
color={focused ? COLORS.primary : '#ccc'} />
)
}}
/>
<Drawer.Screen
name="Elect"
component={WebViewElect}
options={{
drawerIcon: ({ focused, size }) => (
<Entypo
name="new"
size={size}
color={COLORS.danger} />
),
}}
/>
</Drawer.Navigator>
Inside MyBottomTabs:
<Tabs.Navigator initialRouteName="Dashboard" >
{/*Bottom Tab Screens */}
<Tabs.Screen name="Dashboard" component={DashboardStack}/>
<Tabs.Screen name="Refer A Friend" component={WebViewRefer}
options={{
tabBarButton: () => null,
tabBarVisible: false
}}
listeners={({ navigation }) => ({
tabPress: e => {
console.log('Button Pressed')
e.preventDefault();
return navigation.openDrawer();
}
})}
/>
</Tabs.Navigator>

React Native Nested Navigation

import React from 'react';
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs';
import {MaterialCommunityIcons,Feather} from '#expo/vector-icons';
import {VideoTab} from './VideoTab';
import {EbookTab} from './EbookTab';
import {TestTab} from './TestTab';
import {NotesTab} from './NotesTab';
const Bottom = createMaterialBottomTabNavigator();
export const BottomNav = ({navigation,route})=>{
return (
<Bottom.Navigator
initialRouteName="VideoTab"
activeColor="#1ca6d1"
inactiveColor="red"
labeled='true'
barStyle={{ backgroundColor: '#ffffff' }}
>
<Bottom.Screen
name="VideoTab"
component={VideoTab}
options={{
title:'Video',
tabBarLabel: 'Class',
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="lightbulb-on-outline" color={color} size={26} />
),
}}
/>
<Bottom.Screen
name="NotesTab"
component={NotesTab}
options={{
title:'Notes',
tabBarLabel: 'Notes',
tabBarIcon: ({ color }) => (
<Feather name="book" color={color} size={26} />
),
}}
/>
<Bottom.Screen
name="EbookTab"
component={EbookTab}
options={{
tabBarBadge:true,
title:'Ebook',
tabBarLabel: 'QuestionBank',
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="account" color={color} size={26} />
),
}}
/>
<Bottom.Screen
name="TestTab"
component={TestTab}
options={{
title:'Test',
tabBarLabel: 'Test',
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="account" color={color} size={26} />
),
}}
/>
</Bottom.Navigator>
);
}
And this bottom navigation is inside a stack navigator.
Every screen name is a tab screen and every tab screen contain 3 tab.
When I am clicking any tab, then I want to change header title according to tab.
How to create this type of navigation header title in react native?
If you want to have every tab name to be the top try this: https://reactnavigation.org/docs/screen-options-resolution/
Check out the getHeaderTitle function and the switch statement below that - it helped me achieve this behavoir.