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)
作为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)