4

I'd like to have a context menu triggered on long press different places using React Native.

I.e. in a dialer like the default dailer. You can long-click on any contact and get a 'copy number' menu. And also you can long-click on the name of the person once you've opened their 'contact card'.

The straight-forward way needs a lot of copy-pasted boilerplate, both components and handlers.

Is there a better pattern for doing this?

odinho - Velmont
  • 20,922
  • 6
  • 41
  • 33
  • 3
    Specific places or any places? This is a bit too broad question. Can you give some context to it please. – bennygenel Oct 13 '17 at 18:22
  • @bennygenel Yes, it's not a good question. I'm too new to React and React Native. I explained a bit more what I want to do, hope it narrows it down a bit. – odinho - Velmont Oct 14 '17 at 10:33
  • 1
    RNPM in between supports it - see `triggerOnLongPress` / `onAlternativeAction` https://github.com/instea/react-native-popup-menu/blob/master/doc/api.md#menutrigger – sodik Oct 12 '20 at 12:27

2 Answers2

8

All Touchable components (TouchableWithoutFeedback, TouchableOpacity etc.) has a property called onLongPress. You can use this prop to listen for long presses and then show the context menu.

To eliminate code mess and doing lots of copy paste you can separate your context menu as a different component and call it when the long press happen. You can also use an ActionSheet library to show the desired options. React native has a native API for iOS called ActionSheetIOS. If you get a little bit more experience in react and react-native you can create a better logic for this but I'm going to try to give you an example below.

// file/that/contains/globally/used/functions.js

const openContextMenu = (event, user, callback) => {
  ActionSheetIOS.showActionSheetWithOptions({
    options: ['Copy Username', 'Call User', 'Add to favorites', 'Cancel'],
    cancelButtonIndex: [3],
    title: 'Hey',
    message : 'What do you want to do now?'
  }, (buttonIndexThatSelected) => {
    // Do something with result
    if(callback && typeof callback === 'function') callback();
  });
};

export openContextMenu;

import { openContextMenu } from './file/that/contains/globally/used/functions';

export default class UserCard extends React.Component {  
  render() {
    const { userObject } = this.props;
    return(
      <TouchableWithoutFeedback onLongPress={(event) => openContextMenu(event, userObject, () => console.log('Done')}>
        <TouchableWithoutFeedback onLongPress={(event) => openContextMenu(event, userObject, () => console.log('Done'))}>
          <Text>{userObject.name}</Text>
          <Image source={{uri: userObject.profilePic }}  />
        </TouchableWithoutFeedback>
      </TouchableWithoutFeedback>
    );
  }
}
bennygenel
  • 23,896
  • 6
  • 65
  • 78
7

Similarly as the previous answer combine onLongPress with imperative control for popup menu - something like

      <TouchableWithoutFeedback onLongPress={()=>this.menu.open()}>
        <View style={styles.card}>
          <Text>My first contact name</Text>
          <Menu ref={c => (this.menu = c)}>
            <MenuTrigger text="..." />
            <MenuOptions>
               // ...
            </MenuOptions>
          </Menu>
        </View>
      </TouchableWithoutFeedback>

When it comes to a lot of boilerplate - in React you can do your own components that you can reuse everywhere thus reducing boilerplate (and copy&paste)

See full example on https://snack.expo.io/rJ5LBM-TZ

Gianfranco P.
  • 10,049
  • 6
  • 51
  • 68
sodik
  • 4,675
  • 2
  • 29
  • 47