VOOZH about

URL: https://blog.logrocket.com/react-native-contacts-how-to-access-a-devices-contact-list/

โ‡ฑ React Native Contacts: How to access a device's contact list - LogRocket Blog


2021-12-13
1291
#react native
Nitish Sharma
82399
๐Ÿ‘ Image

See how LogRocket's Galileo AI surfaces the most severe issues for you

No signup required

Check it out

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.

๐Ÿ‘ React Native Contacts: How to Access a Device's Contact List

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.

๐Ÿ‘ You can add the key in xcode

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.


Over 200k developers use LogRocket to create better digital experiences

๐Ÿ‘ Image
Learn more โ†’

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:

๐Ÿ‘ Dummy contacts from the simulator

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:

๐Ÿ‘ Contacts from simulator (expo app)

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.

LogRocket: Instantly identify and recreate issues in your React Native apps

๐Ÿ‘ Image

LogRocket's Galileo AI watches sessions for you and and surfaces the technical and usability issues holding back 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.

๐Ÿ‘ Image
๐Ÿ‘ Image
๐Ÿ‘ Image

Stop guessing about your digital experience with LogRocket

Get started for free

Recent posts:

I let React Compiler handle memoization: Hereโ€™s what actually broke

Enabled React Compiler v1.0 on a production Next.js app. Hereโ€™s every warning, breakage, and silent opt-out I documented โ€” and what actually worked.

๐Ÿ‘ Image
Isaac Okoro
Jun 29, 2026 โ‹… 7 min read

TanStack Start RSC vs. Next.js RSC: Performance, DX, and production readiness

We built the same app in TanStack Start RSC and Next.js RSC. TanStack shipped 40% less JS and built 4x faster โ€” but Next.js is still the safer production bet.

๐Ÿ‘ Image
Chizaram Ken
Jun 25, 2026 โ‹… 7 min read

Frontend Wrapped H1 2026: The nine biggest storylines so far

From RSC vulnerabilities and the Vercel breach to TypeScript 7.0 Beta and AI agents โ€” the nine frontend storylines that defined H1 2026, ranked.

๐Ÿ‘ Image
Chizaram Ken
Jun 23, 2026 โ‹… 9 min read

I shipped AI-generated React code: 4 bugs I fixed

AI tools generate working React code fast, but miss race conditions, empty states, debouncing, and accessibility. Hereโ€™s how to catch bugs before production.

๐Ÿ‘ Image
Temitope Oyedele
Jun 22, 2026 โ‹… 10 min read
View all posts

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 now