1
0
mirror of https://github.com/tooot-app/app synced 2025-04-24 07:07:24 +02:00

Fetching now works better

For #490
This commit is contained in:
xmflsct 2023-01-06 22:58:01 +01:00
parent c2aa78fef8
commit 70d57ed830
2 changed files with 131 additions and 147 deletions

View File

@ -4,9 +4,9 @@ import { InfiniteData, useQueryClient } from '@tanstack/react-query'
import { QueryKeyTimeline, TimelineData, useTimelineQuery } from '@utils/queryHooks/timeline' import { QueryKeyTimeline, TimelineData, useTimelineQuery } from '@utils/queryHooks/timeline'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import React, { RefObject, useCallback, useRef, useState } from 'react' import React, { RefObject, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { FlatList, LayoutChangeEvent, Platform, StyleSheet, Text, View } from 'react-native' import { FlatList, Platform, Text, View } from 'react-native'
import { Circle } from 'react-native-animated-spinkit' import { Circle } from 'react-native-animated-spinkit'
import Animated, { import Animated, {
Extrapolate, Extrapolate,
@ -45,10 +45,10 @@ const TimelineRefresh: React.FC<Props> = ({
} }
const fetchingLatestIndex = useRef(0) const fetchingLatestIndex = useRef(0)
const FETCHING_LATEST_MAX = 5
const refetchActive = useRef(false) const refetchActive = useRef(false)
const { refetch, isFetching, isLoading, fetchPreviousPage, hasPreviousPage, isFetchingNextPage } = const { refetch, isFetching, fetchPreviousPage, hasPreviousPage } = useTimelineQuery({
useTimelineQuery({
...queryKey[1], ...queryKey[1],
options: { options: {
getPreviousPageParam: firstPage => getPreviousPageParam: firstPage =>
@ -67,13 +67,14 @@ const TimelineRefresh: React.FC<Props> = ({
} }
return data return data
}, },
onSuccess: () => { onSuccess: async () => {
if (fetchingLatestIndex.current > 0) { if (fetchingLatestIndex.current > 0) {
if (fetchingLatestIndex.current > 5) { if (fetchingLatestIndex.current > FETCHING_LATEST_MAX) {
clearFirstPage() clearFirstPage()
fetchingLatestIndex.current = 0 fetchingLatestIndex.current = 0
} else { } else {
if (hasPreviousPage) { if (hasPreviousPage) {
await new Promise(res => setTimeout(res, 100))
fetchPreviousPage() fetchPreviousPage()
fetchingLatestIndex.current++ fetchingLatestIndex.current++
} else { } else {
@ -102,27 +103,6 @@ const TimelineRefresh: React.FC<Props> = ({
} }
}) })
} }
const prepareRefetch = () => {
refetchActive.current = true
queryClient.setQueryData<InfiniteData<TimelineData> | undefined>(queryKey, data => {
if (data) {
data.pageParams = [undefined]
const newFirstPage: TimelineData = { body: [] }
for (let page of data.pages) {
// @ts-ignore
newFirstPage.body.push(...page.body)
if (newFirstPage.body.length > 10) break
}
data.pages = [newFirstPage]
}
return data
})
}
const callRefetch = async () => {
await refetch()
setTimeout(() => flRef.current?.scrollToOffset({ offset: 1 }), 50)
}
const [textRight, setTextRight] = useState(0) const [textRight, setTextRight] = useState(0)
const arrowY = useAnimatedStyle(() => ({ const arrowY = useAnimatedStyle(() => ({
@ -145,14 +125,6 @@ const TimelineRefresh: React.FC<Props> = ({
})) }))
const arrowStage = useSharedValue(0) const arrowStage = useSharedValue(0)
const onLayout = useCallback(
({ nativeEvent }: LayoutChangeEvent) => {
if (nativeEvent.layout.x + nativeEvent.layout.width > textRight) {
setTextRight(nativeEvent.layout.x + nativeEvent.layout.width)
}
},
[textRight]
)
useAnimatedReaction( useAnimatedReaction(
() => { () => {
if (isFetching) { if (isFetching) {
@ -190,8 +162,32 @@ const TimelineRefresh: React.FC<Props> = ({
}, },
[isFetching] [isFetching]
) )
const wrapperStartLatest = () => {
const runFetchPrevious = () => {
fetchingLatestIndex.current = 1 fetchingLatestIndex.current = 1
fetchPreviousPage()
}
const prepareRefetch = () => {
refetchActive.current = true
queryClient.setQueryData<InfiniteData<TimelineData> | undefined>(queryKey, data => {
if (data) {
data.pageParams = [undefined]
const newFirstPage: TimelineData = { body: [] }
for (let page of data.pages) {
// @ts-ignore
newFirstPage.body.push(...page.body)
if (newFirstPage.body.length > 10) break
}
data.pages = [newFirstPage]
}
return data
})
}
const callRefetch = async () => {
await refetch()
setTimeout(() => flRef.current?.scrollToOffset({ offset: 0 }), 50)
} }
useAnimatedReaction( useAnimatedReaction(
@ -202,42 +198,46 @@ const TimelineRefresh: React.FC<Props> = ({
fetchingType.value = 0 fetchingType.value = 0
switch (data) { switch (data) {
case 1: case 1:
runOnJS(wrapperStartLatest)() runOnJS(runFetchPrevious)()
runOnJS(clearFirstPage)() return
runOnJS(fetchPreviousPage)()
break
case 2: case 2:
runOnJS(prepareRefetch)() runOnJS(prepareRefetch)()
runOnJS(callRefetch)() runOnJS(callRefetch)()
break return
} }
}, },
[] []
) )
const headerPadding = useAnimatedStyle(
() => ({
paddingTop:
fetchingLatestIndex.current !== 0 || (isFetching && !isLoading && !isFetchingNextPage)
? withTiming(StyleConstants.Spacing.M * 2.5)
: withTiming(0)
}),
[fetchingLatestIndex.current, isFetching, isFetchingNextPage, isLoading]
)
return ( return (
<Animated.View style={headerPadding}> <Animated.View
<View style={styles.base}> style={{
{isFetching ? ( position: 'absolute',
<View style={styles.container2}> top: 0,
left: 0,
right: 0,
height: CONTAINER_HEIGHT * 2,
alignItems: 'center'
}}
>
{(fetchingLatestIndex.current || 99) <= FETCHING_LATEST_MAX || refetchActive.current ? (
<View style={{ height: CONTAINER_HEIGHT, justifyContent: 'center' }}>
<Circle size={StyleConstants.Font.Size.L} color={colors.secondary} /> <Circle size={StyleConstants.Font.Size.L} color={colors.secondary} />
</View> </View>
) : ( ) : (
<> <>
<View style={styles.container1}> <View style={{ flex: 1, flexDirection: 'row', height: CONTAINER_HEIGHT }}>
<Text <Text
style={[styles.explanation, { color: colors.primaryDefault }]} style={{
onLayout={onLayout} fontSize: StyleConstants.Font.Size.S,
lineHeight: CONTAINER_HEIGHT,
color: colors.primaryDefault
}}
onLayout={({ nativeEvent }) => {
if (nativeEvent.layout.x + nativeEvent.layout.width > textRight) {
setTextRight(nativeEvent.layout.x + nativeEvent.layout.width)
}
}}
children={t('refresh.fetchPreviousPage')} children={t('refresh.fetchPreviousPage')}
/> />
<Animated.View <Animated.View
@ -258,39 +258,25 @@ const TimelineRefresh: React.FC<Props> = ({
} }
/> />
</View> </View>
<View style={styles.container2}> <View style={{ height: CONTAINER_HEIGHT, justifyContent: 'center' }}>
<Text <Text
style={[styles.explanation, { color: colors.primaryDefault }]} style={{
onLayout={onLayout} fontSize: StyleConstants.Font.Size.S,
lineHeight: CONTAINER_HEIGHT,
color: colors.primaryDefault
}}
onLayout={({ nativeEvent }) => {
if (nativeEvent.layout.x + nativeEvent.layout.width > textRight) {
setTextRight(nativeEvent.layout.x + nativeEvent.layout.width)
}
}}
children={t('refresh.refetch')} children={t('refresh.refetch')}
/> />
</View> </View>
</> </>
)} )}
</View>
</Animated.View> </Animated.View>
) )
} }
const styles = StyleSheet.create({
base: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
height: CONTAINER_HEIGHT * 2,
alignItems: 'center'
},
container1: {
flex: 1,
flexDirection: 'row',
height: CONTAINER_HEIGHT
},
container2: { height: CONTAINER_HEIGHT, justifyContent: 'center' },
explanation: {
fontSize: StyleConstants.Font.Size.S,
lineHeight: CONTAINER_HEIGHT
}
})
export default TimelineRefresh export default TimelineRefresh

View File

@ -129,13 +129,11 @@ const Timeline: React.FC<Props> = ({
/> />
) )
} }
maintainVisibleContentPosition={ {...(!isLoading && {
isFetching maintainVisibleContentPosition: {
? {
minIndexForVisible: 0 minIndexForVisible: 0
} }
: undefined })}
}
{...androidRefreshControl} {...androidRefreshControl}
{...customProps} {...customProps}
/> />