handle off screen visibility observer.

This commit is contained in:
Hailey
2024-07-04 09:20:33 -07:00
parent 4f02da96c8
commit e499ea0ed6
2 changed files with 73 additions and 57 deletions
+1 -10
View File
@@ -25,7 +25,6 @@ import {LoadMoreRetryBtn} from '#/view/com/util/LoadMoreRetryBtn'
import {CenteredView} from '#/view/com/util/Views'
import {FeedItem} from './FeedItem'
import hairlineWidth = StyleSheet.hairlineWidth
import {isWeb} from '#/platform/detection'
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
@@ -183,15 +182,7 @@ export function Feed({
refreshing={isPTRing}
onRefresh={onRefresh}
onEndReached={onEndReached}
onEndReachedThreshold={
/*
NOTE:
web's intersection observer struggles with the 2x threshold
and leads to missed pagination, so we keep it <1
-prf
*/
isWeb ? 0.6 : 2
}
onEndReachedThreshold={2}
onScrolledDownChange={onScrolledDownChange}
contentContainerStyle={s.contentContainer}
// @ts-ignore our .web version only -prf
+72 -47
View File
@@ -63,53 +63,7 @@ function ListImpl<ItemT>(
}: ListProps<ItemT>,
ref: React.Ref<ListMethods>,
) {
const contextScrollHandlers = useScrollHandlers()
const pal = usePalette('default')
const {isMobile} = useWebMediaQueries()
if (!isMobile) {
contentContainerStyle = addStyle(
contentContainerStyle,
styles.containerScroll,
)
}
const isEmpty = !data || data.length === 0
let headerComponent: JSX.Element | null = null
if (ListHeaderComponent != null) {
if (isValidElement(ListHeaderComponent)) {
headerComponent = ListHeaderComponent
} else {
// @ts-ignore Nah it's fine.
headerComponent = <ListHeaderComponent />
}
}
let footerComponent: JSX.Element | null = null
if (ListFooterComponent != null) {
if (isValidElement(ListFooterComponent)) {
footerComponent = ListFooterComponent
} else {
// @ts-ignore Nah it's fine.
footerComponent = <ListFooterComponent />
}
}
let emptyComponent: JSX.Element | null = null
if (ListEmptyComponent != null) {
if (isValidElement(ListEmptyComponent)) {
emptyComponent = ListEmptyComponent
} else {
// @ts-ignore Nah it's fine.
emptyComponent = <ListEmptyComponent />
}
}
if (headerOffset != null) {
style = addStyle(style, {
paddingTop: headerOffset,
})
}
const [prevDataLength, setPrevDataLength] = React.useState(data?.length)
const getScrollableNode = React.useCallback(() => {
if (containWeb) {
@@ -184,6 +138,77 @@ function ListImpl<ItemT>(
}
}, [containWeb])
// Whenever we get new data, we want to make sure that the onEndReached threshold will be *below* the current scroll
// bottom position. If it is not the IntersectionObserver will never fire the onEndReached threshold for us - since
// we've already scrolled past the component.
const callOnEndReachedIfNeeded = () => {
const node = getScrollableNode()
if (!node || !onEndReached || !onEndReachedThreshold || !data?.length) {
return
}
const scrollViewHeight = node.clientHeight
const scrollContainerHeight = node.scrollHeight
const scrollPos = node.scrollY
const thresholdPx = onEndReachedThreshold * scrollViewHeight
if (scrollContainerHeight - thresholdPx <= scrollPos) {
onEndReached({distanceFromEnd: 0})
}
setPrevDataLength(data?.length)
}
if (data?.length !== prevDataLength) {
callOnEndReachedIfNeeded()
}
const contextScrollHandlers = useScrollHandlers()
const pal = usePalette('default')
const {isMobile} = useWebMediaQueries()
if (!isMobile) {
contentContainerStyle = addStyle(
contentContainerStyle,
styles.containerScroll,
)
}
const isEmpty = !data || data.length === 0
let headerComponent: JSX.Element | null = null
if (ListHeaderComponent != null) {
if (isValidElement(ListHeaderComponent)) {
headerComponent = ListHeaderComponent
} else {
// @ts-ignore Nah it's fine.
headerComponent = <ListHeaderComponent />
}
}
let footerComponent: JSX.Element | null = null
if (ListFooterComponent != null) {
if (isValidElement(ListFooterComponent)) {
footerComponent = ListFooterComponent
} else {
// @ts-ignore Nah it's fine.
footerComponent = <ListFooterComponent />
}
}
let emptyComponent: JSX.Element | null = null
if (ListEmptyComponent != null) {
if (isValidElement(ListEmptyComponent)) {
emptyComponent = ListEmptyComponent
} else {
// @ts-ignore Nah it's fine.
emptyComponent = <ListEmptyComponent />
}
}
if (headerOffset != null) {
style = addStyle(style, {
paddingTop: headerOffset,
})
}
const nativeRef = React.useRef<HTMLDivElement>(null)
React.useImperativeHandle(
ref,