You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用react-native-contacts包时通讯录长列表加载卡顿如何优化?

性能优化方案

当前使用KeyboardAwareScrollView配合map一次性渲染全部475条联系人节点,所有节点无论是否在可视区域都会被挂载到渲染树,占用大量内存和计算资源,是卡顿的核心原因,可按以下步骤优化:


1. 替换ScrollView为FlatList实现虚拟列表

FlatList只会渲染当前可视区域的节点,超出可视区域的节点会被回收复用,400+条数据的场景下性能提升非常明显,替换后的渲染代码示例:

import { FlatList } from 'react-native';
// 抽离列表项组件,避免不必要重渲染
const ContactItem = React.memo(({ item, onPress }) => {
  return (
    <TouchableOpacity onPress={() => onPress(item)}>
      <FriendsComponent
        isChecked={item.isChecked}
        nameSurname={item.nameSurname}
      />
    </TouchableOpacity>
  )
})

// 渲染部分替换为以下代码
<KeyboardAwareScrollView showsVerticalScrollIndicator={false}>
  <Box flex={1} mt={20}>
    <Box ml={10} mb={5}>
      <Text>Total: {this.state.contacts?.length} </Text>
    </Box>
    <FlatList
      data={this.state.contactsTemp}
      keyExtractor={(item) => item.recordID}
      renderItem={({ item }) => <ContactItem item={item} onPress={this.checkContact} />}
      removeClippedSubviews={true}
      // 按实际FriendsComponent高度调整数值,提前固定布局避免动态计算
      getItemLayout={(data, index) => ({length: 60, offset: 60 * index, index})}
      initialNumToRender={15}
      maxToRenderPerBatch={10}
      windowSize={5}
    />
  </Box>
</KeyboardAwareScrollView>

keyExtractor不要用index作为唯一标识,用唯一的recordID可以大幅提升列表节点复用效率。


2. 优化数据处理逻辑

现有数据处理代码存在冗余计算和逻辑漏洞,优化后可减少初始化耗时:

getContacts() {
  // 封装公共处理逻辑,避免两端重复代码
  const processContacts = (rawContacts, nameKey) => {
    return rawContacts.map(contact => ({
      nameSurname: contact[nameKey],
      nameSurnameLower: contact[nameKey].toLowerCase(), // 提前存储小写姓名,避免排序时重复计算
      recordID: contact.recordID,
      phone: contact.phoneNumbers[0],
      isChecked: false,
    })).sort((a, b) => a.nameSurnameLower.localeCompare(b.nameSurnameLower))
  }

  if (Platform.OS == 'android') {
    PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.READ_CONTACTS, {
      title: 'Contacts',
      message: 'This app would like to view your contacts.',
      buttonPositive: 'Please accept bare mortal',
    }).then(grantResult => {
      // 权限授权成功后再获取通讯录,避免权限被拒绝时无效执行
      if (grantResult === PermissionsAndroid.RESULTS.GRANTED) {
        Contacts.getAllWithoutPhotos().then(contacts => {
          const processedContacts = processContacts(contacts, 'displayName')
          this.setState({
            contacts: processedContacts,
            contactsTemp: processedContacts,
            loaded: true
          })
        })
      }
    })
  } else {
    Contacts.getAllWithoutPhotos().then(contacts => {
      const processedContacts = processContacts(contacts, 'givenName')
      this.setState({
        contacts: processedContacts,
        contactsTemp: processedContacts,
        loaded: true
      })
    })
  }     
}

3. 优化选中状态更新逻辑

避免选中联系人时全量重渲染整个列表,优化checkContact方法:

checkContact = (targetItem) => {
  const updateIsChecked = (list) => {
    return list.map(item => {
      if (item.recordID === targetItem.recordID) {
        return {...item, isChecked: !item.isChecked}
      }
      return item
    })
  }
  this.setState({
    contactsTemp: updateIsChecked(this.state.contactsTemp),
    contacts: updateIsChecked(this.state.contacts)
  })
}

4. 组件层级优化

检查FriendsComponent的实现,避免不必要的嵌套层级,组件本身用React.memo包裹,仅当props变化时才触发重渲染。

完成以上优化后,400+条联系人的滑动、选中操作流畅度会有明显提升。


内容的提问来源于stack exchange,提问作者tes krmtstk4

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 19:06:02