React Native Contacts: How to access a device’s contact list

From making phone calls to finding friends on social media platforms, contacts hold a critical place in the digital world. The big, fat book of phone numbers from yesteryear is now a compact list on a smartphone. Every person has their own unique set of contacts consisting of phone numbers, emails, etc.

In this guide, we’ll explore React Native Contacts, a powerful contacts component that can fetch, update and add new contacts, using your React Native app. We’ll also go through a similar module for Expo.

To follow along, you should be familiar with the basics of React Native and Expo, including JSX, components (class and functional), and styling.

You could simply copy and paste the code blocks from this guide, but I would suggest reading through the whole tutorial for a complete understanding. This guide assumes you’ve already done the basic setup for you app.

What is React Native Contacts?

React Native Contacts is a module that provides functionality to create, fetch, update, and delete contacts in a React Native app for iOS and Android. It uses various promises to do all the tasks mentioned above. This helps it complete all the required tasks without putting too much pressure on the UI thread of the app.

Setting up React Native Contacts (iOS and Android)

There isn’t much setup required for this module because autolinking handles most of the work. But for the permissions required for the contacts, we need to make slight additions after the linking.

First, we need to add the module to our React Native project.

$ yarn add react-native-contacts

In the case of Android, autolinking handles all the work. The one thing we might need to check is the addition of the <uses-permission tag for contacts in AndroidManifest.xml:

<uses-permission android:name="android.permission.WRITE_CONTACTS" />

For iOS, first we need to install the pods, in the iOS/ directory:

$ pod install

The next step is to add a key to info.plist:

Privacy - Contacts Usage Description

You can add a string, which is a message that should show up on the permission pop-up on iOS.

Accessing contacts in a bare React Native app

To access the contacts, first we need to import the contacts module.

import Contacts from 'react-native-contacts';

To access the contacts from the phone, we’ll use the getAll promise of the module.

Contacts.getAll().then(contacts => {
      // setContacts(contacts);
});

We’ll receive the data in a for of JSON array with each object structured something like this:

{
      "birthday":{
         "day":20,
         "month":1,
         "year":1978
      },
      "company":"Creative Consulting",
      "emailAddresses":[
         [
            "Object"
         ]
      ],
      "familyName":"Bell",
      "givenName":"Kate",
      "hasThumbnail":false,
      "imAddresses":[
         
      ],
      "jobTitle":"Producer",
      "middleName":"",
      "phoneNumbers":[
         [
            "Object"
         ],
         [
            "Object"
         ]
      ],
      "postalAddresses":[
         [
            "Object"
         ]
      ],
      "recordID":"177C371E-701D-42F8-A03B-C61CA31627F6",
      "thumbnailPath":"",
      "urlAddresses":[
         [
            "Object"
         ]
      ]
   },

Above is an example a contact that was received from the getAll promise.

To present the data in a list, we’ll use the FlatList component from React Native. Feel free to use any listing component you prefer.

Below is the example code for the list.

**ContactsList.js**

import React, {useEffect, useState} from 'react';
import {FlatList, View, Text, StyleSheet} from 'react-native';
import Contacts from 'react-native-contacts';
import {Contact} from '.';
const ContactsList = () => {
  const [contacts, setContacts] = useState([]);
  useEffect(() => {
    Contacts.getAll().then(contacts => {
      setContacts(contacts);
    });
  }, []);
  const keyExtractor = (item, idx) => {
    return item?.recordID?.toString() || idx.toString();
  };
  const renderItem = ({item, index}) => {
    return <Contact contact={item} />;
  };
  return (
    <FlatList
      data={contacts}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      style={styles.list}
    />
  );
};
const styles = StyleSheet.create({
  list: {
    flex: 1,
  },
});
export default ContactsList;

**Contact.js**

import React from 'react';
import {View, Text, StyleSheet} from 'react-native';
const Contact = ({contact}) => {
  return (
    <View style={styles.contactCon}>
      <View style={styles.imgCon}>
        <View style={styles.placeholder}>
          <Text style={styles.txt}>{contact?.givenName[0]}</Text>
        </View>
      </View>
      <View style={styles.contactDat}>
        <Text style={styles.name}>
          {contact?.givenName} {contact?.middleName && contact.middleName + ' '}
          {contact?.familyName}
        </Text>
        <Text style={styles.phoneNumber}>
          {contact?.phoneNumbers[0]?.number}
        </Text>
      </View>
    </View>
  );
};
const styles = StyleSheet.create({
  contactCon: {
    flex: 1,
    flexDirection: 'row',
    padding: 5,
    borderBottomWidth: 0.5,
    borderBottomColor: '#d9d9d9',
  },
  imgCon: {},
  placeholder: {
    width: 55,
    height: 55,
    borderRadius: 30,
    overflow: 'hidden',
    backgroundColor: '#d9d9d9',
    alignItems: 'center',
    justifyContent: 'center',
  },
  contactDat: {
    flex: 1,
    justifyContent: 'center',
    paddingLeft: 5,
  },
  txt: {
    fontSize: 18,
  },
  name: {
    fontSize: 16,
  },
  phoneNumber: {
    color: '#888',
  },
});
export default Contact;

**index.js**

import ContactsList from './contactsList';
import Contact from './contact';
export default ContactsList;
export {Contact};

The output should look something like this:

Accessing contacts in a React Native Expo app

The concept of fetching contacts in Expo is same as above with a slight change in the received data structure.

Again, first we need to import the module:

import * as Contacts from "expo-contacts";

To access the contacts from the phone, we will use the getAll promise of the module.

const { data } = await Contacts.getContactsAsync({
          fields: [Contacts.PHONE_NUMBERS],
});

We will receive the data in a for of JSON array with each object structured something like this:

{
  "company": "Creative Consulting",
  "contactType": "person",
  "firstName": "Kate",
  "id": "177C371E-701D-42F8-A03B-C61CA31627F6",
  "imageAvailable": false,
  "jobTitle": "Producer",
  "lastName": "Bell",
  "name": "Kate Bell",
  "phoneNumbers": Array [
    Object {
      "countryCode": "us",
      "digits": "5555648583",
      "id": "EF48385D-28C2-48DE-AAB3-A81BC5F16981",
      "label": "mobile",
      "number": "(555) 564-8583",
    },
    Object {
      "countryCode": "us",
      "digits": "4155553695",
      "id": "3CD5F927-B150-4104-918B-C26DD6AC811B",
      "label": "main",
      "number": "(415) 555-3695",
    },
  ],
}

Above is the example contact that was received from the getAll promise.

To present the data in a list, we will use the FlatList component. Again, you can use any listing component.

The files and the structure of the dummy component is kept the same as the bare React Native example.

Here is the example code for the list:

**ContactsList.js**

import React, { useEffect, useState } from "react";
import { FlatList, View, Text, StyleSheet } from "react-native";
import Contact from "./contact";
import * as Contacts from "expo-contacts";
const ContactsList = () => {
  const [contacts, setContacts] = useState([]);
  useEffect(() => {
    (async () => {
      const { status } = await Contacts.requestPermissionsAsync();
      if (status === "granted") {
        const { data } = await Contacts.getContactsAsync({
          fields: [Contacts.PHONE_NUMBERS],
        });
        if (data.length > 0) {
          setContacts(data);
          console.log(data[0]);
        }
      }
    })();
  }, []);
  const keyExtractor = (item, idx) => {
    return item?.id?.toString() || idx.toString();
  };
  const renderItem = ({ item, index }) => {
    return <Contact contact={item} />;
  };
  return (
    <FlatList
      data={contacts}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      style={styles.list}
    />
  );
};
const styles = StyleSheet.create({
  list: {
    flex: 1,
  },
});
export default ContactsList;

**Contact.js**

import React from "react";
import { View, Text, StyleSheet } from "react-native";
const Contact = ({ contact }) => {
  return (
    <View style={styles.contactCon}>
      <View style={styles.imgCon}>
        <View style={styles.placeholder}>
          <Text style={styles.txt}>{contact?.name[0]}</Text>
        </View>
      </View>
      <View style={styles.contactDat}>
        <Text style={styles.name}>{contact?.name}</Text>
        <Text style={styles.phoneNumber}>
          {contact?.phoneNumbers[0]?.number}
        </Text>
      </View>
    </View>
  );
};
const styles = StyleSheet.create({
  contactCon: {
    flex: 1,
    flexDirection: "row",
    padding: 5,
    borderBottomWidth: 0.5,
    borderBottomColor: "#d9d9d9",
  },
  imgCon: {},
  placeholder: {
    width: 55,
    height: 55,
    borderRadius: 30,
    overflow: "hidden",
    backgroundColor: "#d9d9d9",
    alignItems: "center",
    justifyContent: "center",
  },
  contactDat: {
    flex: 1,
    justifyContent: "center",
    paddingLeft: 5,
  },
  txt: {
    fontSize: 18,
  },
  name: {
    fontSize: 16,
  },
  phoneNumber: {
    color: "#888",
  },
});
export default Contact;

**index.js**

import ContactsList from './contactsList';
import Contact from './contact';
export default ContactsList;
export {Contact};

Here’s the output of the above code:

Conclusion

React Native Contacts and Expo Contacts are both great tools for fetching and manipulating the contacts on a user’s device.

In this tutorial, we went over how to fetch contacts in both a bare and Expo React Native app. If you want to explore more options, I would suggest trying out the expo-contacts module of Expo modules to play with contacts in your bare React Native app.


You can also checkout this post over Logrocket here.