FlatList多次加载数据
我有下一个简单的页面:
type Props = {
getPostsUseCase: GetPostsUseCase
}
const renderItem = ({item}: ListRenderItemInfo<Post>) => (
<NewsPost title={item.msg} />
)
const HomeScreen = ({getPostsUseCase}: Props) => {
const [isLoading, setLoading] = useState(true)
const [shouldFetch, setShouldFetch] = useState(true)
const [since, setSince] = useState<number | null>(null)
const [posts, setPosts] = useState<Post[]>([])
const fetchMore = useCallback(() => setShouldFetch(since != null), [since])
useEffect(() => {
// Prevent fetching for other state changes
if (!shouldFetch) return
getPostsUseCase
.execute({
limit: 15,
since: since,
})
.then((page: Page<Post>) => {
setPosts(oldPosts => [...oldPosts, ...page.data])
setSince(page.next)
})
.catch((error: string) => console.error(error))
.finally(() => {
setLoading(false)
setShouldFetch(false)
})
}, [getPostsUseCase, shouldFetch, since])
const onEndReachedCalledDuringMomentum = useRef(true)
const onEndReachedHandler = () => {
if (!onEndReachedCalledDuringMomentum.current) {
fetchMore()
onEndReachedCalledDuringMomentum.current = true
}
}
return (
<SafeAreaView style={styles.frame}>
{isLoading ? (
<Text>Loading...</Text>
) : (
<FlatList
style={styles.list}
data={posts}
renderItem={renderItem}
keyExtractor={item => item.id.toString()}
onEndReachedThreshold={0.1}
initialNumToRender={15}
onEndReached={onEndReachedHandler}
onMomentumScrollBegin={() => {
onEndReachedCalledDuringMomentum.current = false
}}
/>
)}
</SafeAreaView>
)
}
export default HomeScreen
但是,它有两个问题:
- 它在开始时加载两个页面(30 个项目,而不是 15,对后端的两个请求)
- 它在滚动时多次加载整个集合(总共 30 个项目,它渲染了 90 个项目) )
问题出在哪里?我发现很多主题都有类似的问题,我尝试了他们的解决方案,但没有帮助(例如,这个)
我是 React Native 的菜鸟。老实说,我什至不明白我的问题和他们的解决方案,以及为什么它们不起作用。
UDP
最后,我想出了一个可行的解决方案,但仍然有一个烦人的时刻:
type Props = {
getPostsUseCase: GetPostsUseCase
}
type Data = {
posts: Post[]
next: number | null
}
const renderItem = ({item}: ListRenderItemInfo<Post>) => (
<NewsPost title={item.msg} />
)
const HomeScreen = ({getPostsUseCase}: Props) => {
const [isLoading, setLoading] = useState(true)
const [data, setData] = useState<Data>({
posts: [],
next: null,
})
const loadData = () => {
if (!isLoading && data.next == null) return
getPostsUseCase
.execute({
limit: 15,
since: data.next,
})
.then((page: Page<Post>) => {
setData(oldPage => ({
posts: [...oldPage.posts, ...page.data],
next: page.next,
}))
})
.catch((error: string) => console.error(error))
.finally(() => setLoading(false))
}
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(loadData, [])
return (
<SafeAreaView style={styles.frame}>
{isLoading ? (
<Text>Loading...</Text>
) : (
<FlatList
style={styles.list}
data={data?.posts}
renderItem={renderItem}
keyExtractor={item => item.id.toString()}
onEndReachedThreshold={0.1}
onEndReached={loadData}
/>
)}
</SafeAreaView>
)
}
export default HomeScreen
ESlint 需要在 useEffect< 中指定
loadData
/代码> 依赖项。我通过 // eslint-disable-next-line react-hooks/exhaustive-deps
禁用了该警告,但这是一个肮脏的伎俩......
如何修复解决方案,我不需要禁用ESLint 规则?
I have the next simple page:
type Props = {
getPostsUseCase: GetPostsUseCase
}
const renderItem = ({item}: ListRenderItemInfo<Post>) => (
<NewsPost title={item.msg} />
)
const HomeScreen = ({getPostsUseCase}: Props) => {
const [isLoading, setLoading] = useState(true)
const [shouldFetch, setShouldFetch] = useState(true)
const [since, setSince] = useState<number | null>(null)
const [posts, setPosts] = useState<Post[]>([])
const fetchMore = useCallback(() => setShouldFetch(since != null), [since])
useEffect(() => {
// Prevent fetching for other state changes
if (!shouldFetch) return
getPostsUseCase
.execute({
limit: 15,
since: since,
})
.then((page: Page<Post>) => {
setPosts(oldPosts => [...oldPosts, ...page.data])
setSince(page.next)
})
.catch((error: string) => console.error(error))
.finally(() => {
setLoading(false)
setShouldFetch(false)
})
}, [getPostsUseCase, shouldFetch, since])
const onEndReachedCalledDuringMomentum = useRef(true)
const onEndReachedHandler = () => {
if (!onEndReachedCalledDuringMomentum.current) {
fetchMore()
onEndReachedCalledDuringMomentum.current = true
}
}
return (
<SafeAreaView style={styles.frame}>
{isLoading ? (
<Text>Loading...</Text>
) : (
<FlatList
style={styles.list}
data={posts}
renderItem={renderItem}
keyExtractor={item => item.id.toString()}
onEndReachedThreshold={0.1}
initialNumToRender={15}
onEndReached={onEndReachedHandler}
onMomentumScrollBegin={() => {
onEndReachedCalledDuringMomentum.current = false
}}
/>
)}
</SafeAreaView>
)
}
export default HomeScreen
However, it has two problems:
- It loads two pages on start (30 items, not 15, two requests to the backend)
- It loads entire collection multiple times on scrolling (there 30 items totally, it rendered 90)
Where is the problem? I found a lot of topics with similar problem, I tried their solutions but it didn't help (for example, this)
I am a noobie in React Native. To be honest, I don't even understand my problem and their solutions, and why they don't work.
UDP
Finally, I came up with a working solution but there is still an annoying moment:
type Props = {
getPostsUseCase: GetPostsUseCase
}
type Data = {
posts: Post[]
next: number | null
}
const renderItem = ({item}: ListRenderItemInfo<Post>) => (
<NewsPost title={item.msg} />
)
const HomeScreen = ({getPostsUseCase}: Props) => {
const [isLoading, setLoading] = useState(true)
const [data, setData] = useState<Data>({
posts: [],
next: null,
})
const loadData = () => {
if (!isLoading && data.next == null) return
getPostsUseCase
.execute({
limit: 15,
since: data.next,
})
.then((page: Page<Post>) => {
setData(oldPage => ({
posts: [...oldPage.posts, ...page.data],
next: page.next,
}))
})
.catch((error: string) => console.error(error))
.finally(() => setLoading(false))
}
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(loadData, [])
return (
<SafeAreaView style={styles.frame}>
{isLoading ? (
<Text>Loading...</Text>
) : (
<FlatList
style={styles.list}
data={data?.posts}
renderItem={renderItem}
keyExtractor={item => item.id.toString()}
onEndReachedThreshold={0.1}
onEndReached={loadData}
/>
)}
</SafeAreaView>
)
}
export default HomeScreen
ESlint requires to specify loadData
in useEffect
dependencies. I disabled that warning by // eslint-disable-next-line react-hooks/exhaustive-deps
but it's a dirty trick...
How to fix the solution to I was not needed disabling an ESLint rule?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论