使用expo-contacts获取联系人时pending callbacks过多错误的解决方法
解决Expo Contacts获取联系人时的"Excessive number of pending callbacks"错误
这个错误通常源于未限制useEffect执行时机(重复触发异步操作)、未正确等待异步方法完成,以及组件卸载后仍有异步回调尝试更新状态导致的回调泄漏。以下是具体解决步骤和优化后的代码:
关键修复点
- 给
useEffect添加空依赖数组[],确保仅在组件挂载时执行一次,避免重复触发异步操作积累回调。 - 为
Contacts.getContactsAsync()添加await,该方法是异步的,必须等待完成才能获取有效数据,否则会产生未处理的Promise导致泄漏。 - 使用
AbortController取消未完成的异步请求,防止组件卸载后回调继续执行。 - 统一用
async/await处理AsyncStorage操作,简化逻辑并便于错误处理。
优化后的完整代码
import * as Contacts from 'expo-contacts'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { useEffect, useState } from 'react'; function ContactListScreen() { const [contacts, setContacts] = useState([]); const [phone, setPhone] = useState(null); const [name, setName] = useState(null); useEffect(() => { const abortController = new AbortController(); const signal = abortController.signal; const fetchData = async () => { try { // 请求联系人权限 const { status } = await Contacts.requestPermissionsAsync(); if (status === 'granted') { // 等待联系人获取完成,传入signal支持取消 const { data } = await Contacts.getContactsAsync({ fields: [Contacts.Fields.PhoneNumbers], signal, }); if (data.length > 0) { setContacts(data); } } // 获取本地存储的凭证 const result = await AsyncStorage.getItem('Credentials'); if (result !== null) { const credentials = JSON.parse(result); setPhone(credentials.phone); setName(credentials.fullName); } else { setPhone(null); } } catch (error) { // 忽略取消操作的错误,避免控制台冗余报错 if (error.name !== 'AbortError') { console.error('数据获取失败:', error); } } }; fetchData(); // 组件卸载时取消所有未完成的异步操作 return () => abortController.abort(); }, []); // 空依赖数组,确保仅执行一次 // 你的组件UI渲染逻辑 return ( // ... 此处为UI代码 ); }
额外说明
- 如果你的联系人数量极大,还可以考虑使用
Contacts.getContactsAsync的pageSize和page参数进行分页获取,避免一次性加载大量数据导致的性能问题和回调堆积。 - 若仍出现问题,检查是否有其他未清理的异步操作或重复触发的useEffect,确保所有异步逻辑都有明确的执行时机和清理机制。
内容的提问来源于stack exchange,提问作者bytebunny
相关产品推荐
相关产品推荐

