React Native:整个 FlatList 在每次更改时都会重新渲染,即使使用 React.memo

M Y*_*M Y 2 reactjs react-native expo react-native-flatlist react-hooks

在过去的几天里,我一直在努力解决这个问题:我有一个创建者列表存储在一个数组中,还有另一个用于关注创建者的数组,但是当用户“关注”创建者时,整个 FlatList 会重新渲染。这是一个问题,因为我为每个创建者加载 3 个图像,因此每次用户关注/取消关注创建者时都会出现大量闪烁和滞后。

我尝试过使用 React.memo 但它似乎不起作用,而且我觉得我的代码的其他部分也可能存在问题。任何帮助将不胜感激!

获取第一次渲染的数据:

  useMemo(() => {
    setRefreshing(true);
    return onValue(ref(db, '/users/' + auth?.currentUser?.uid + '/vendorsFollowing'), async (querySnapShot) => {
      let data = (await querySnapShot.val()) || {};
      let vendorData = { ...data };
      setVendorsFollowing(Object.keys(vendorData))
      setRefreshing(false);
    });
  }, []);

  useMemo(() => {
    setRefreshing(true);
    return onValue(ref(db, '/users'), (querySnapShot) => {
      let data = querySnapShot.val() || {};
      let vendorList = { ...data };
      setVendorArray(vendorList);
      setFilteredVendorArray(vendorList);
      setRefreshing(false);
    });
  }, []);
Run Code Online (Sandbox Code Playgroud)

供应商项目:

const VendorItem = React.memo(({ vendor }: any) => {
    // image stuff
    const [imgUrl1, setImgUrl1] = useState<string | undefined>(undefined);
    const ref1 = ref_storage(storage, vendor.uid + '_1.png');

    const [imgUrl2, setImgUrl2] = useState<string | undefined>(undefined);
    const ref2 = ref_storage(storage, vendor.uid + '_2.png');

    const [imgUrl3, setImgUrl3] = useState<string | undefined>(undefined);
    const ref3 = ref_storage(storage, vendor.uid + '_3.png');

    if (!blocked) {
      getDownloadURL(ref1)
        .then((url) => {
          setImgUrl1(url);
        })
        .catch((error) => {
        });

      getDownloadURL(ref2)
        .then((url) => {
          setImgUrl2(url);
        })
        .catch((error) => {
        });

      getDownloadURL(ref3)
        .then((url) => {
          setImgUrl3(url);
        })
        .catch((error) => {
        });
    }

return(
   <View style={[styles.eventImageContainer, { marginVertical: (imgUrl1 || imgUrl2 || 
   imgUrl3) && 5 }]}>
          {imgUrl1 && <Image source={{ uri: imgUrl1 }} style={styles.vendorImage} 
   imageStyle={{ borderRadius: 20 }} />}
          {imgUrl2 && <Image source={{ uri: imgUrl2 }} style={styles.vendorImage} 
   imageStyle={{ borderRadius: 20 }} />}
          {imgUrl3 && <Image source={{ uri: imgUrl3 }} style={styles.vendorImage} 
   imageStyle={{ borderRadius: 20 }} />}
        </View>

   // updateStarred basically adds vendor.uid to vendorsFollowing and to the database
   <TouchableOpacity onPress={() => { updateStarred(vendor.uid) }}>
      <Icon
         name={vendorsFollowing.includes(vendor.uid) ? 'bookmark' : 'bookmark-o'}
         size={25}
         color="white"
      />
   </TouchableOpacity>
)
}, (prevProps, nextProps) => {
   if (vendorsFollowing.includes(prevProps.vendor.uid) === vendorsFollowing.includes(nextProps.vendor.uid)) return true;
    return false;
  });
Run Code Online (Sandbox Code Playgroud)

编辑:平面列表:

<FlatList
            initialNumToRender={7}
            contentContainerStyle={{ paddingBottom: 325 }}
            showsVerticalScrollIndicator={false}
            style={{ marginTop: 10 }}
            data={Object.keys(filteredVendorArray)}
            keyExtractor={(item) => filteredVendorArray[item].uid}
            refreshControl={<RefreshControl refreshing={refreshing} onRefresh={loadNewData} />}
            renderItem={({ item }) => (
              <View style={{ backgroundColor: '#FFfF8F3', marginBottom: 20 }}>
                <VendorItem vendor={filteredVendorArray[item]} />
              </View>
            )}/>
Run Code Online (Sandbox Code Playgroud)

Kir*_*kov 8

作为renderItem属性,您提供一个始终创建并触发新渲染的匿名函数。代替它:

renderItem={({ item }) => (
<View style={{ backgroundColor: '#FFfF8F3', marginBottom: 20 }}>
  <VendorItem vendor={filteredVendorArray[item]} />
</View>
)}
Run Code Online (Sandbox Code Playgroud)

和:

const renderItemFn = useCallback(() => ({ item }) => (
<VendorItem vendor={filteredVendorArray[item]} />
))
...
renderItem={renderItemFn}
Run Code Online (Sandbox Code Playgroud)

keyExtractor 中也存在同样的问题。

同时将 View 移至View style={{ backgroundColor: '#FFfF8F3', marginBottom: 20 }}VendorItem 因为它没有记忆

更多平面列表优化示例: https: //www.obytes.com/blog/a-guide-to-optimizing-flatlists-in-react-native

另一个可能的问题是你的记忆,如果vendor是一个复杂的对象,你需要添加一个自定义比较函数:

const customComparator = (prevProps, nextProps) => {
  // add your logic for comprassion
  return nextProps. vendor === prevProps. vendor;
};

export default React.memo(VendorItem, customComparator);
Run Code Online (Sandbox Code Playgroud)