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.
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.
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.
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:
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:
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.
LogRocket is a React Native monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your React Native apps.
LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.
Start proactively monitoring your React Native apps — try LogRocket for free.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to implement one-way and two-way data binding in Vue.js, using v-model and advanced techniques like defineModel for better apps.
Compare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
2 Replies to "React Native Contacts: How to access a device’s contact list"
In AndroidManifest.xml, this is required in order to user Contacts.getAll():
Without this, no read permissions causes the Android app to crash
Better than their official documentation!