- bounty将在5天后过期**。此问题的答案可获得+50声望奖励。Jankapunkt正在寻找此问题的更详细答案:请解释为什么FlatList阻止点击Pressable Svg,直到所有屏幕外项目呈现,以及这是否与我的FlatList配置或Svg有关。
我有一个FlatList
,它接收最多50个元素的(不可变的)数据,并且它使用react-native-svg
在每个列表项Svg中呈现。
图形的一部分被用于选择元素的Pressable
组件包裹。
现在的问题是,我不能选择任何元素,直到FlatList
遍历了所有50个项目。
我不明白的是,屏幕外的项目甚至没有呈现,它只是容器。一旦它全部呈现,我可以点击元素,涟漪效应显示和事件被激发。
规格:
- 博览会@46.0.0
- 在0.69.6时React天然
- 在18.0.0时React
- 通过
expo start --no-dev --minify
运行android,然后在Expo Go中打开
复制:
import React, { useEffect, useState } from 'react'
import { FlatList } from 'react-native'
import { Foo } from '/path/to/Foo'
import { Bar } from '/path/to/Bar'
export const Overview = props => {
const [data, setData] = useState(null)
// 1. fetching data
useEffect(() => {
// load data from api
const loaded = [{ id: 0, type: 'foo' }, { id: 1, type: 'bar' }] // make a list of ~50 here
setData(loaded)
}, [])
if (!data?.length) {
return null
}
// 2. render list item
const onPressed = () => console.debug('pressed')
const renderListItem = ({ index, item }) => {
if (item.type === 'foo') {
return (<Foo key={`foo-${index}`} onPressed={onPressed} />)
}
if (item.type === 'bar') {
return (<Foo key={`bar-${index}`} onPressed={onPressed} />)
}
return null
}
// at this point data exists but will not be changed anymore
// so theoretically there should be no re-render
return (
<FlatList
data={data}
renderItem={renderListItem}
inverted={true}
decelerationRate="fast"
disableIntervalMomentum={true}
removeClippedSubviews={true}
persistentScrollbar={true}
keyExtractor={flatListKeyExtractor}
initialNumToRender={10}
maxToRenderPerBatch={10}
updateCellsBatchingPeriod={100}
getItemLayout={flatListGetItemLayout}
/>
)
}
}
// optimized functions
const flatListKeyExtractor = (item) => item.id
const flatListGetItemLayout = (data, index) => {
const entry = data[index]
const length = entry && ['foo', 'bar'].includes(entry.type)
? 110
: 59
return { length, offset: length * index, index }
}
svg组件,仅显示Foo
,因为Bar
在结构上相似,并且该问题影响以下两者:
import React from 'react'
import Svg, { G, Circle } from 'react-native-svg'
const radius = 25
const size = radius * 2
// this is a very simplified example,
// rendering a pressable circle
const FooSvg = props => {
return (
<Pressable
android_ripple={rippleConfig}
pressRetentionOffset={0}
hitSlop={0}
onPress={props.onPress}
>
<Svg
style={props.style}
width={size}
height={size}
viewBox={`0 0 ${radius * 2} ${radius * 2}`}
>
<G>
<Circle
cx='50%'
cy='50%'
stroke='black'
strokeWidth='2'
r={radius}
fill='red'
/>
</G>
</Svg>
</Pressable>
)
}
const rippleConfig = {
radius: 50,
borderless: true,
color: '#00ff00'
}
// pure component
export const Foo = React.memo(FooSvg)
渲染性能本身是相当不错的,但我不明白,为什么我需要等待长达两秒钟,直到我可以按下圆圈,尽管他们已经渲染。
任何帮助都将不胜感激。
编辑
快速滚动列表时,我得到:
VirtualizedList: You have a large list that is slow to update - make sure your renderItem function renders components that follow React performance best practices like PureComponent, shouldComponentUpdate, etc. {"contentLength": 4740, "dt": 4156, "prevDt": 5142}
然而,组件已经被记忆化了(PureComponent),不是很复杂。一定还有另一个问题。
硬件
我用iPad进行了交叉测试,如果描述的问题没有,似乎只发生在Android上。
1条答案
按热度按时间7dl7o3gd1#
请忽略语法错误。
这是平面列表的问题。平面列表不适合在一个像联系人列表这样的地方呈现更大的列表。平面列表只适合像Facebook那样从教堂的API获取数据。从API获取10个元素,然后在下一个调用中再获取10个。
要呈现大量项目,如联系人列表(超过1000个)或类似的内容,请使用https://bolan9999.github.io/react-native-largelist/#/en/