I have just started learning React Native yesterday and while I find it extremely infuriating at the moment as I have been developing for the web exclusively but I have really been enjoying the new elements and everything.
I have been using the react navigation bottom drawers with expo and I would like to know how I could render a function that contains my icon.
So my drawer looks like this –
<Tab.Navigator
initialRouteName="Home"
activeColor="#fff"
tabBar={props => <MyTabBar {...props} />}
shifting="false"
sceneContainerStyle={{ marginBottom: 2 }}>
<Tab.Screen name="Home" component={HomeScreen}
options={{
tabBarLabel: '',
tabBarIcon: (() => <LogoutIcon size={20} />)
}}
/>
<Tab.Screen name="Settings" component={LoginScreen} />
<Tab.Screen name="Profile" component={LoginScreen} />
<Tab.Screen name="Logout" component={LoginScreen} />
</Tab.Navigator>
As you can see I’m passing an Icon component to a screen which I’m unable to render in the MyTabBar
component, because I’m not sure how to render a function directly? If
function MyTabBar({ state, descriptors, navigation }) {
return (
<View style={{ flexDirection: 'row', position: 'absolute', bottom: 30, right: 20, left: 20, backgroundColor: '#550080', borderRadius: 200, borderWidth: 2, borderColor: '#3c005a', padding: 0 }}>
{state.routes.map((route, index) => {
const { options } = descriptors[route.key];
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel
: options.title !== undefined
? options.title
: route.name;
const isFocused = state.index === index;
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate({ name: route.name, merge: true });
}
};
const onLongPress = () => {
navigation.emit({
type: 'tabLongPress',
target: route.key,
});
};
console.log(options)
const tabBarIcon = options.tabBarIcon
console.log(tabBarIcon)
return (
<View className='flex-1 p-5 flex-row w-full text-center items-center justify-center border-r border-[#3c005a]'
key={label}>
<TouchableOpacity
accessibilityRole="button"
accessibilityState={isFocused ? { selected: true } : {}}
accessibilityLabel={options.tabBarAccessibilityLabel}
onPress={onPress}
style={{ flex: 1, alignSelf: 'center', alignContent: 'center', justifyContent: 'center' }}
>
<View className='w-full items-center justify-center mb-2'>
<Text> {tabBarIcon}</Text>**// Trying to render the icon here.**
</View>
</TouchableOpacity>
</View>
);
})}
</View>
);
}
From my console logs, I can tell that the screen I passed the tabBarIcon
option has the following output :
Object {
"headerShown": false,
"tabBarIcon": [Function tabBarIcon],
"tabBarLabel": "",
"tabBarStyle": Object {
"backgroundColor": "purple",
"borderColor": "red",
"borderRadius": 200,
"borderWidth": "2px",
"bottom": 50,
"height": 80,
"left": 20,
"position": "absolute",
"right": 20,
},
}
2
Answers
For anyone who needs this in future reference, I got it to work by using the
@expo/vector-icons
pack.This is what I simply did -
The TabBar component -
MainComponent -
Result: -
First off I’d say if you’re new to React Native, you shouldn’t be messing around with the custom tab bar. That’s really just reserved for wild stuff, and all the styling you’ve got there seems like it could be done normally.
If you still want to use the custom tab bar, the first thing I would point to is how in React Native you can’t put anything other than text inside of a Text tag. Also, you’re passing the options object an inline function for the tabBarIcon. Therefore you’ve gotta call it. You’re looking for something more like this: