Access Contacts in React Native

Step-by-Step Guide to Accessing and Displaying Contacts in React Native Application

In this guide, we will cover how to access and display device contacts in React Native. This feature can be crucial for many apps, such as messaging or social networks. Let’s get started!

Prerequisites

To follow the post, you will need a React Native application, which can be easily created using this command:

npx react-native init ContactsList

Pre-built Contacts Screen

For this example we will be using one of the WithFrame’s pre-built contacts screen.

Installation

If you’re using yarn, use the following command:

yarn add react-native-contacts

For NPM users we have this command:

npm install react-native-contacts --save

Now let’s install Pods for iOS with the following command:

npx pod-install

On React Native 0.60+ the CLI autolink feature links the module while building the app.

Permissions

Once the installation is done, we have to add permission strings to AndroidManifest.xml and Info.plist as shown below:

<uses-permission android:name="android.permission.READ_CONTACTS" />
<key>NSContactsUsageDescription</key>
<string>ContactsList needs your permission to access your contacts</string>

Step 1: Load all contacts

In order to load all device contacts we have to use the getAll() method on the Contacts module.

Because this action is asynchronous, we have to call it inside a useEffect and write the received data into a state.

import Contacts from 'react-native-contacts';
const [contacts, setContacts] = React.useState<Contacts.Contact[] | null>(
  null,
);
React.useEffect(() => {
  if (Platform.OS === 'android') {
    PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.READ_CONTACTS, {
      title: 'Contacts',
      message: 'ContactsList app would like to access your contacts.',
      buttonPositive: 'Accept',
    }).then(value => {
      if (value === 'granted') {
        Contacts.getAll().then(setContacts);
      }
    });
  } else {
    Contacts.getAll().then(setContacts);
  }
}, []);

Step 2: Group all contacts alphabetically by family name

Lodash library provides an excellent helper function for grouping; however, in our case, we will use good old-fashioned JavaScript.

First, let’s run a reduce on the array of contacts and convert them into an object like this: { "A": [CONTACT, CONTACT], "B": [CONTACT], ... }

Then, with the help of Object.entries(), we can convert it back into an array with the following structure: [{ letter: "A", items: [CONTACT, CONTACT] }] and sort all of the items in alphabetic order.

For performance reasons, we will wrap this code in a React.useMemo hook. It will now only run when the contacts array is changed.

const sections = React.useMemo(() => {
  if (!contacts) {
    return null;
  }

  const sectionsMap = contacts.reduce<Record<string, Contacts.Contact[]>>(
    (acc, contact) => {
      const {familyName} = contact;
      const [firstLetter] = familyName;

      return Object.assign(acc, {
        [firstLetter]: [...(acc[firstLetter] || []), contact],
      });
    },
    {},
  );

  return Object.entries(sectionsMap)
    .map(([letter, items]) => ({
      letter,
      items: items.sort((a, b) => a.familyName.localeCompare(b.familyName)),
    }))
    .sort((a, b) => a.letter.localeCompare(b.letter));
}, [contacts]);

Step 3: Display ActivityIndicator until the data is available

As mentioned before, Contacts.getAll() action is asynchronous, which is why we will display an ActivityIndicator until the data is available.

if (!sections) {
  return (
    <View
      style={{
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
        backgroundColor: '#fff',
      }}>
      <ActivityIndicator />
    </View>
  );
}

Step 4: Update WithFrame’s template to use Contact’s properties

In this template, we’re using properties like img and name, however, they don’t exist on the Contact object.

For our template to work with the Contact object, let’s add the following local properties:

  • name — a combination of givenName and familyName
  • img — defined as thumbnailPath
  • phone — use the first item in the phoneNumbers array or - if the array is empty.
{sections.map(({letter, items}) => (
  <View style={styles.section} key={letter}>
    <Text style={styles.sectionTitle}>{letter}</Text>
    <View style={styles.sectionItems}>
      {items.map(
        (
          {givenName, familyName, phoneNumbers, thumbnailPath},
          index,
        ) => {
          const name = `${givenName} ${familyName}`;
          const phone = phoneNumbers.length
            ? phoneNumbers[0].number
            : '-';
          const img = thumbnailPath;

          return (
            <View key={index} style={styles.cardWrapper}>
              <TouchableOpacity
                onPress={() => {
                  // handle onPress
                }}>
                <View style={styles.card}>
                  {img ? (
                    <Image
                      alt=""
                      resizeMode="cover"
                      source={{uri: img}}
                      style={styles.cardImg}
                    />
                  ) : (
                    <View style={[styles.cardImg, styles.cardAvatar]}>
                      <Text style={styles.cardAvatarText}>
                        {name[0]}
                      </Text>
                    </View>
                  )}
              
                  <View style={styles.cardBody}>
                    <Text style={styles.cardTitle}>{name}</Text>
              
                    <Text style={styles.cardPhone}>{phone}</Text>
                  </View>
              
                  <View style={styles.cardAction}>
                    <FeatherIcon
                      color="#9ca3af"
                      name="chevron-right"
                      size={22}
                    />
                  </View>
                </View>
              </TouchableOpacity>
            </View>
          );
        },
      )}
    </View>
  </View>
))}

We hope you enjoyed this content and now better understand how to load and use contacts in the React Native Application.

Final React Native application code can be found in our GitHub repo