Home > database >  How to return a function as an Icon React Native
How to return a function as an Icon React Native

Time:07-24

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,
  },
}

CodePudding user response:

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:

<View>
  {tabBarIcon()}
  <Text>{options.title}</Text>
</View>

CodePudding user response:

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 -

    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) {
                                // The `merge: true` option makes sure that the params inside the tab screen are preserved
                                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-4 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-'>
<Ionicons name={tabBarIcon} size={22} color="#ccc" className='text-white bg-black' />
    
                                    </View>
    
                                </TouchableOpacity>
                            </View>
                        );
                    })}
                </View>
            );
        }

MainComponent -

<Tab.Navigator
            initialRouteName="Home"
            activeColor="#fff"
            tabBar={props => <MyTabBar {...props} />}
            shifting="false"
            screenOptions={{
                headerShown: false,
                tabBarStyle: {
                    position: 'absolute',
                    bottom: 50,
                    right: 20,
                    left: 20,
                    height: 80,
                    borderRadius: 200,
                    backgroundColor: 'purple',
                    borderColor: 'red',
                    borderWidth: '2px',

                },

            }}
            sceneContainerStyle={{ marginBottom: 2 }}

        >
            <Tab.Screen name="Home" component={HomeScreen}
                options={{
                    tabBarLabel: 'Home',
                    showIcon: true,
                    tabBarIcon: 'home'
                }}
            />

</Tab.Navigator>

Result: -

enter image description here

  • Related