В этом руководстве мы расскажем, как получить доступ и отобразить контакты устройства в React Native. Эта функция может иметь решающее значение для многих приложений, таких как обмен сообщениями или социальные сети. Давайте начнем!

Предпосылки

Чтобы следить за постом, вам понадобится приложение React Native, которое можно легко создать с помощью этой команды:

npx react-native init ContactsList

В этом примере мы будем использовать один из предустановленных экранов контактов WithFrame.

Монтаж

Если вы используете пряжу, используйте следующую команду:

yarn add react-native-contacts

Для пользователей NPM у нас есть эта команда:

npm install react-native-contacts --save

Теперь давайте установим Pods для iOS с помощью следующей команды:

npx pod-install

В React Native 0.60+ функция автоссылки CLI связывает модуль при создании приложения.

Разрешения

После завершения установки мы должны добавить строки разрешений в AndroidManifest.xml и Info.plist, как показано ниже:

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

Шаг 1. Загрузите все контакты

Чтобы загрузить все контакты устройства, мы должны использовать метод getAll() в модуле «Контакты».

Поскольку это действие асинхронно, мы должны вызывать его внутри useEffect и записывать полученные данные в состояние.

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);
  }
}, []);

Шаг 2. Сгруппируйте все контакты в алфавитном порядке по фамилии.

Библиотека Lodash предоставляет отличную вспомогательную функцию для группировки; однако в нашем случае мы будем использовать старый добрый JavaScript.

Во-первых, давайте запустим сокращение массива контактов и преобразуем их в такой объект: { "A": [CONTACT, CONTACT], "B": [CONTACT], ... }

Затем с помощью Object.entries() мы можем преобразовать его обратно в массив со следующей структурой: [{ letter: "A", items: [CONTACT, CONTACT] }] и отсортировать все элементы в алфавитном порядке.

По соображениям производительности мы поместим этот код в хук React.useMemo. Теперь он будет работать только при изменении массива contacts.

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]);

Шаг 3. Отображайте ActivityIndicator до тех пор, пока данные не будут доступны.

Как упоминалось ранее, действие Contacts.getAll() является асинхронным, поэтому мы будем отображать индикатор активности до тех пор, пока данные не будут доступны.

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

Шаг 4. Обновите шаблон WithFrame, чтобы использовать свойства контакта.

В этом шаблоне мы используем такие свойства, как img и name, однако их нет в объекте Contact.

Чтобы наш шаблон работал с объектом Contact, добавим следующие локальные свойства:

  • name — комбинация givenName и familyName
  • img — определяется как thumbnailPath
  • phone — использовать первый элемент в массиве phoneNumbers или -, если массив пуст.
{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>
))}

Мы надеемся, что вам понравился этот контент, и теперь вы лучше понимаете, как загружать и использовать контакты в приложении React Native.

Окончательный код приложения React Native можно найти в нашем репозитории GitHub.

Этот экран и многие другие можно найти на нашем сайте: WithFrame React Native Components