React Navigation Tab.Screen set Component as name - react-native

What i want to do is the following when using the react navigation package.
The docs allow the following:
<Tab.Screen name="name" component={FeedScreen} />
what i want to achieve is this:
<Tab.Screen name={<NameMarkdown />} component={FeedScreen} />
because i want to render markdown as the name of a tab in my application.
is there a way to solve the problem?

The name prop only accepts the string name of the screen you can't pass the component into a name prop.
To give customize the style of your tab you can use it like this
<Tab.Navigator
screenOptions={tabScreenOptions}
tabBarOptions={tabBarOptions}
>
<Tab.Screen name="name" component={FeedScreen} />
tabBarOptions = {
showLabel: false,
style: styles.tabContainer,
tabStyle: styles.tabStyle,
};
tabScreenOptions = props => {
const { route } = props;
return {
tabBarIcon: ({ focused }) => <TabIcon {...{ route, focused }} />,
};
};
const TabIcon = ({ focused, route }) => (
// Here you can use your own component according to your need
<Image
source={Images.tabs[route.name]}
style={{ tintColor: focused ? Colors.primary : Colors.white214 }}
/>
);
Hope this helps you out.

Related

How to add drawerIcon inside options in React Native

Here is my code:
<Drawer.Screen
name="Home"
component={StackNavigator}
options={({route}) => {
const routeName = getFocusedRouteNameFromRoute(route) ?? 'Billing';
if (sideMenuDisabledScreens.includes(routeName))
return {swipeEnabled: false};
}}
/>
I am implementing drawer navigator in my application and I want to add icon for drawer item home. Inside options I have added route to disable drawer for particular screens. After adding the route disable code I am not able to mention icons for drawerIcon. How can I do this?
i get your point, you can have both properties just like this
options={({route}) => {
const routeName = getFocusedRouteNameFromRoute(route) ?? 'Billing';
if (sideMenuDisabledScreens.includes(routeName))
return {swipeEnabled: false};
},
{
drawerIcon: // add your comp here,
title:" THIS is possible",
}
}
Hope ite helps. feel free for doubts
Add drawerIcon property like the following:
drawerIcon: ({ tintColor }) => (
<Image
source={require('./chats-icon.png')}
style={[{ tintColor: tintColor }]}
/>
),

How to pass props to a screen component in react navigation

I have a navigator that looks like this and I'm trying to pass informations to all the tabs below it.
import {createMaterialTopTabNavigator} from '#react-navigation/material-top-tabs';
const Tab = createMaterialTopTabNavigator();
<Tab.Navigator
swipeEnabled={false}
initialRouteName="TabMapScreen"
screenProps={user} // I've tried this
initialLayout={{width: Dimensions.get('window').width}}
>
<Tab.Screen
name="TabMapScreen"
component={PostsTab}
/>
<Tab.Screen
name="TabMapScreen"
component={() => <PostsTab props={user} />} // also tried this
/>
</Tab.Navigator>
what's the correct solution to passing props to a screen, straight from the navigator?
You can use the initialParams
<Tab.Screen
name="TabMapScreen"
component={PostsTab}
initialParams={{userData: user}} //User data is just an alias
/>
Just try this
<Tab.Screen name="TabMapScreen">
{props => <A123 {...props} props={user} />}
</Tab.Screen>
I think it is what you want !
There is two ways to do so:
Route params
This is if you need to change the props/parameters dynamically at navigate time:
function HomeScreen({ navigation }) {
return <View>
<Button
title="Go to Details"
onPress={() => {
navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
});
}}
/>
</View>
}
function DetailsScreen({ route, navigation }) {
/* 2. Get the param */
const { itemId, otherParam } = route.params
...
}
Initial params
This way is if you need to pass props/params when the route is defined
<Stack.Screen
name="Details"
component={DetailsScreen}
initialParams={{ itemId: 42 }}
/>
Full documentation here

createBottomTabNavigator hide some tabs

I have following tab navigator defined for react native 6 for a screen, so there are 3 screens in total A, B and C. But I don't want to show "C" since it can be reached by navigating from A.
const Tab = createBottomTabNavigator();
const Main: () => React$Node = props => {
return (
<Tab.Navigator
<Tab.Screen name={Routes.A} component={A} />
<Tab.Screen name={Routes.B} component={B} />
<Tab.Screen name={Routes.C} component={C} />
</Tab.Navigator>
);
};
there has been a solution using style to hide component C. but after upgrading react from 5 to 6, it has stopped to work and I read the documentation and try using new properties without success,
tabBarOptions={{
showLabel: false,
style: {
height: Dimensions.DIMENSION_BOTTOM_TAB_BAR_HEIGHT,
width: '200%',
paddingBottom: 0,
},
visible: false,
}}>
so what is the react 6 way of setting width so component C can be hided? Another question is that (I am new to react), is there any way adding component C into the route for current screen without even having it as <Tab.Screen>. This is the content from ComponentA, the ideal solution here is to add ComponentC here but I tried add component binding in MenuItem without success, it complains there is no such route handled by any navigator. Is is not the same as using createStackNavigator
const Menu: () => React$Node = props => {
return (Colors.COLOR_BLACK]}
<VScrollLayout contentContainerStyle={{flexGrow: 1}} style={styles.content}>
<View style={styles.innerContainer}>
<MenuItem
image={<Image source={Images.ICON_C} />}
text={i18n.t('C')}
route={Routes.C}
navigation={props.navigation}
/>
</View>
</VScrollLayout>
);
};
The correct navigation would be to put the TabNavigation as root (main) navigation and in each tab you have a StackNavigation. If you need to access screen C from both A and B, you can add them in both StackNavigations. (A + C and B + C).
Edit:
code:
const TabAStack = createStackNavigator();
function TabAStackNavigation() {
return (
<TabAStack.Navigator >
<TabAStack.Screen name={Routes.A} component={A} />
<TabAStack.Screen name={Routes.C} component={C} />
</TabAStack.Navigator>
);
}
const TabBStack = createStackNavigator();
function TabAStackNavigation() {
return (
<TabAStack.Navigator >
<TabAStack.Screen name={Routes.B} component={B} />
<TabAStack.Screen name={Routes.C} component={C} />
</TabAStack.Navigator>
);
}
const Tab = createBottomTabNavigator();
const Main: () => React$Node = props => {
return (
<Tab.Navigator
<Tab.Screen name={Routes.TabA} component={TabAStackNavigation} />
<Tab.Screen name={Routes.TabB} component={TabBStackNavigation} />
</Tab.Navigator>
);
};
solve the problem by setting extra width for the tabs that I want to show
<Tab.Screen name={Routes.A} component={A} options={{ tabBarStyle: { width: '500%' } }}/>
<Tab.Screen name={Routes.B} component={B} options={{ tabBarStyle: { width: '500%' } }}/>
<Tab.Screen name={Routes.C} component={C} options={{ tabBarStyle: { width: '200%' } }}/>
I totally understand it is an ugly solution, but it will stay before I learn how to add ComponentC into VScrollLayout

React Native getting navigation prop in a regular object

I have a navigation component where my screens are give a header component
<Stack.Screen
name="AddNewHabitScreen"
component={AddNewHabitScreen}
options={{ ...HeaderBar, title: "New Habits" }}
/>
The HeaderBar is just a simple object with option configurations
const HeaderBar = {
...
headerRight: () => (
<TouchableOpacity onPress={navigate(route)}>
<Image
source={require('../../assets/icons/B_icon_header_info.png')}
/>
</TouchableOpacity>
),
Since it's not a class or functional component I'm not sure how to use hooks or props to give the route information so it can navigate correctly. How would I go about doing this?
Something like
const HeaderBar = ({navigation}) {
...
headerRight: (navigation) => (
<TouchableOpacity onPress={navigation.navigate(route)}>
<Image
source={require('../../assets/icons/B_icon_header_info.png')}
/>
</TouchableOpacity>
),

React Navigation V5 does not receive focused parameter when using custom bottomTab component

I am currently trying to implement a custom tabBar design into my react native app which is using React Navigation 5 as the navigation library. Everything is working correctly, except that my tabBarIcons don't receive any props, so i cannot determine whether i have to show the active or inactive tabIcon. Whenever i use a default tabbar i do receive the props, so there must be something wrong in my custom tabbar. I did follow the docs though, and only find the instruction to emit the 'tabPress' event. I do however think that i should emit more events to get the correct focused prop. I have set up the navigator like this:
const Tabs = createBottomTabNavigator();
export default () => (
<Tabs.Navigator tabBar={TabBarComponent} initialRouteName="Home">
<Tabs.Screen
name="Home"
component={HomeScreen}
options={{
tabBarIcon: ({ focused }) => {
// The props here are {}, so focused is undefined.
const icon = focused
? require('images/iconOverviewRed.png')
: require('images/iconOverviewGrey.png');
return <Image source={icon} />;
},
}}
/>
<Tabs.Screen
name="Overview"
component={OverviewScreen}
options={{
tabBarIcon: props => {
console.log(props);
return <Image source={require('images/logoRed.png')} />;
},
}}
/>
<Tabs.Screen
name="Account"
component={AccountScreen}
options={{
tabBarIcon: ({ focused }) => {
const icon = focused
? require('images/iconAccountRed.png')
: require('images/iconAccountGrey.png');
return <Image source={icon} resizeMethod="resize" />;
},
}}
/>
</Tabs.Navigator>
);
And this is my custom tabBar compnent:
const TabBar = ({ navigation, state, descriptors }: any) => {
return (
<View style={styles.container}>
{state.routes.map((route: any) => {
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!event.defaultPrevented) {
navigation.dispatch({
...TabActions.jumpTo(route.name),
target: state.key,
});
}
};
return (
<TabIcon
key={route.key}
Icon={descriptors[route.key].options.tabBarIcon}
onPress={onPress}
isBig={route.name === 'Home'}
/>
);
})}
</View>
);
};
const TabIcon = ({ onPress, Icon, key, isBig }: any) => {
return (
<TouchableWithoutFeedback key={key} onPress={onPress}>
<View style={isBig ? styles.bigTab : styles.defaultTab} key={key}>
<Icon />
</View>
</TouchableWithoutFeedback>
);
};
Thanks in advance.
descriptors[route.key].options just gives you the options as you have specified them. If you log the value of descriptors[route.key].options.tabBarIcon, you'll see that it prints the function that you have specified.
In your custom tab bar, it's upto you to use the option as you need. Since it's a function here, you'll have to call it and pass desired arguments.
descriptors[route.key].options.tabBarIcon({ focused: state.index === index })
This also means that you fully control the option. You can put whatever type you'd like, function, a require statement directly etc. and then use that. You also don't have to call it tabBarIcon, you can call it whatever you want.