From bf4c279b969acc180d76bf7f2834efbf997a5b0f Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Thu, 14 Dec 2023 19:25:00 +0000 Subject: [PATCH] Add scroll handler --- src/view/com/pager/Pager.web.tsx | 4 +- src/view/com/util/List.web.tsx | 127 ++++++++++++++++++------------- 2 files changed, 75 insertions(+), 56 deletions(-) diff --git a/src/view/com/pager/Pager.web.tsx b/src/view/com/pager/Pager.web.tsx index 88bc4a7bf5..7ec2926670 100644 --- a/src/view/com/pager/Pager.web.tsx +++ b/src/view/com/pager/Pager.web.tsx @@ -49,9 +49,7 @@ export const Pager = React.forwardRef(function PagerImpl( onSelect: onTabBarSelect, })} {React.Children.map(children, (child, i) => ( - + {child} ))} diff --git a/src/view/com/util/List.web.tsx b/src/view/com/util/List.web.tsx index 203f771a27..f8e57abad4 100644 --- a/src/view/com/util/List.web.tsx +++ b/src/view/com/util/List.web.tsx @@ -3,6 +3,7 @@ import {FlatListProps, ScrollView, StyleSheet, View} from 'react-native' import {addStyle} from 'lib/styles' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' export type ListMethods = FlatList_INTERNAL export type ListProps = Omit< @@ -100,37 +101,58 @@ function ListImpl( [], ) - const onVisible = React.useCallback(() => { - onEndReached?.({ - distanceFromEnd: onEndReachedThreshold || 0, - }) - }, [onEndReachedThreshold, onEndReached]) + const [isVisible, setIsVisible] = React.useState(false) + + React.useEffect(() => { + if (!isVisible) { + return + } + function handleScroll() { + // TODO + } + window.addEventListener('scroll', handleScroll) + return () => window.removeEventListener('scroll', handleScroll) + }, [isVisible]) return ( - - - {header} - {(data as Array).map((item, index) => ( - - key={keyExtractor!(item, index)} - item={item} - index={index} - renderItem={renderItem} - extraData={extraData} - /> - ))} - {onEndReached && ( - - )} - {footer} - - + { + setIsVisible(newIsVisible) + }}> + + + {header} + {(data as Array).map((item, index) => ( + + key={keyExtractor!(item, index)} + item={item} + index={index} + renderItem={renderItem} + extraData={extraData} + /> + ))} + {onEndReached && ( + { + if (isVisible) { + onEndReached?.({ + distanceFromEnd: onEndReachedThreshold || 0, + }) + } + }} + /> + )} + {footer} + + + ) } @@ -159,38 +181,43 @@ let Row = function RowImpl({ } Row = React.memo(Row) -let Tail = ({ +let Visibility = ({ threshold = 0, - onVisible, + onVisibleChange, + children, }: { threshold?: number | null | undefined - onVisible: () => void + onVisibleChange: (isVisible: boolean) => void + children?: React.ReactNode }): React.ReactNode => { const tailRef = React.useRef(null) + const isIntersecting = React.useRef(false) + + const handleIntersection = useNonReactiveCallback( + (entries: IntersectionObserverEntry[]) => { + entries.forEach(entry => { + if (entry.isIntersecting !== isIntersecting.current) { + isIntersecting.current = entry.isIntersecting + onVisibleChange(entry.isIntersecting) + } + }) + }, + ) React.useEffect(() => { - const observer = new IntersectionObserver( - entries => { - entries.forEach(entry => { - if (entry.isIntersecting) { - onVisible() - } - }) - }, - { - rootMargin: (threshold || 0) * 100 + '%', - }, - ) + const observer = new IntersectionObserver(handleIntersection, { + rootMargin: (threshold || 0) * 100 + '%', + }) const tail: Element | null = tailRef.current! observer.observe(tail) return () => { observer.unobserve(tail) } - }, [onVisible, threshold]) + }, [handleIntersection, threshold]) - return + return {children} } -Tail = React.memo(Tail) +Visibility = React.memo(Visibility) export const List = memo(React.forwardRef(ListImpl)) as ( props: ListProps & {ref?: React.Ref}, @@ -201,12 +228,6 @@ const styles = StyleSheet.create({ borderLeftWidth: 1, borderRightWidth: 1, }, - container: { - width: '100%', - maxWidth: 600, - marginLeft: 'auto', - marginRight: 'auto', - }, containerScroll: { width: '100%', maxWidth: 600,