WillKre
WillKre

Reputation: 6158

How to add a button inside react-navigation Drawer (BETWEEN existing buttons)

To add an extra Drawer button that doesn't link to a route above or below a button in DrawerItemList is as easy as doing:

  <Drawer.Navigator initialRouteName="Home" drawerContent={props => {
    return (
      <DrawerContentScrollView {...props}>
        <DrawerItemList {...props} />
        <DrawerItem label="Logout" onPress={() => props.navigation.navigate("Login")} />
      </DrawerContentScrollView>
    )
  }}>
    <Drawer.Screen name="Home" component={Home}/>
    <Drawer.Screen name="About" component={About} />
  </Drawer.Navigator>

But now I need to add a custom button (like the Logout one, with a custom onPress that doesn't just go to a route, but navigates to Home and calls a couple of functions) between the Home and About buttons.

So my end button result with regards to the buttons on the Drawer should be:

-- Home

-- Custom

-- About

-- Logout

I'd need to somehow break up DrawerItemList but not sure how.

Any ideas how I can achieve this?

Snack can be found here

(Using react-navigation > v5)

Upvotes: 4

Views: 2596

Answers (3)

Christian Orth
Christian Orth

Reputation: 4673

The easiest way to achieve this, is just to not use the DrawerItemList at all.

Simple example without any styling (see Snack):

<Drawer.Navigator
    initialRouteName="Home"
    drawerContent={(props) => {
      return (
        <DrawerContentScrollView {...props}>
          <Button title="Home"onPress={() => props.navigation.navigate("Home")} />
          <Button title="Custom" onPress={() => console.log('Custom Logic')} />
          <Button title="About" onPress={() => props.navigation.navigate("About")} />
          <Button title="Logout" onPress={() => console.log('CUSTOM LOGOUT FUNCTION')} />
        </DrawerContentScrollView>
      );
    }}>
    <Drawer.Screen name="Home" component={PlaceholderPage} />
    <Drawer.Screen name="About" component={PlaceholderPage} />
  </Drawer.Navigator>

Upvotes: 2

Hossein Mohammadi
Hossein Mohammadi

Reputation: 1473

I did it in my case.

Add this to drawer items

        <DrawerItem
          {...props}
          onPress={()=> {
             navigation.navigate('home');
             //.    do other things
          }} 
          label={"Custome"}
          icon={() => <Icon name="custome" size={25} color={colors.jasmine} />}
          style={props.itemStyle}
        />

Upvotes: 0

Guruparan Giritharan
Guruparan Giritharan

Reputation: 16334

To begin with , the code of DrawerItemList doesnt allow anything else except for screens to be there.

But its just another component that you have to pass.

So the easiest way to handle this would be to create your own version of DrawerItemList using the source code and have the option to pass a custom onPress function.

The custom component would look like this, I've commented the places that i modified.

import * as React from 'react';
import {
  CommonActions,
  DrawerActions,
  DrawerNavigationState,
  ParamListBase,
  useLinkBuilder,
} from '@react-navigation/native';

import { DrawerItem } from '@react-navigation/drawer';

export default function CustomDrawerList({
  state,
  navigation,
  descriptors,
  activeTintColor,
  inactiveTintColor,
  activeBackgroundColor,
  inactiveBackgroundColor,
  itemStyle,
  labelStyle,
}: Props) {
  const buildLink = useLinkBuilder();

  return state.routes.map((route, i) => {
    const focused = i === state.index;
    //Access the custom onPress that is passed as an option
    const { title, drawerLabel, drawerIcon, onPress } = descriptors[route.key].options;
  
    return (
      <DrawerItem
        key={route.key}
        label={
          drawerLabel !== undefined
            ? drawerLabel
            : title !== undefined
            ? title
            : route.name
        }
        icon={drawerIcon}
        focused={focused}
        activeTintColor={activeTintColor}
        inactiveTintColor={inactiveTintColor}
        activeBackgroundColor={activeBackgroundColor}
        inactiveBackgroundColor={inactiveBackgroundColor}
        labelStyle={labelStyle}
        style={itemStyle}
        to={buildLink(route.name, route.params)}
        onPress={
          //if onPress is available use that or call the usual navigation dispatch
          // i also passed the navigation so that we can use it in our custom calls
          onPress
            ? () => onPress(navigation)
            : () => {
                navigation.dispatch({
                  ...(focused
                    ? DrawerActions.closeDrawer()
                    : CommonActions.navigate(route.name)),
                  target: state.key,
                });
              }
        }
      />
    );
  });
}

And the drawer would look like this, we pass the onPress as an option

 <Drawer.Navigator
    initialRouteName="Home"
    drawerContent={(props) => {
      return (
        <DrawerContentScrollView {...props}>
          <CustomDrawerList {...props} />
        </DrawerContentScrollView>
      );
    }}>
    <Drawer.Screen name="Home" component={PlaceholderPage} />
    <Drawer.Screen name="Custom" component={PlaceholderPage} options={{
      onPress:()=>alert(123)
    }}/>
    <Drawer.Screen name="About" component={PlaceholderPage} />
  </Drawer.Navigator>

You can check the snack here https://snack.expo.io/@guruparan/custom-button-in-drawer

Upvotes: 5

Related Questions