Add scroll handler

This commit is contained in:
Dan Abramov
2023-12-14 19:25:00 +00:00
parent a132040a76
commit bf4c279b96
2 changed files with 75 additions and 56 deletions
+1 -3
View File
@@ -49,9 +49,7 @@ export const Pager = React.forwardRef(function PagerImpl(
onSelect: onTabBarSelect, onSelect: onTabBarSelect,
})} })}
{React.Children.map(children, (child, i) => ( {React.Children.map(children, (child, i) => (
<View <View style={selectedPage === i ? s.flex1 : s.hidden} key={`page-${i}`}>
style={selectedPage === i ? s.flex1 : {display: 'none'}}
key={`page-${i}`}>
{child} {child}
</View> </View>
))} ))}
+47 -26
View File
@@ -3,6 +3,7 @@ import {FlatListProps, ScrollView, StyleSheet, View} from 'react-native'
import {addStyle} from 'lib/styles' import {addStyle} from 'lib/styles'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
export type ListMethods = FlatList_INTERNAL export type ListMethods = FlatList_INTERNAL
export type ListProps<ItemT> = Omit< export type ListProps<ItemT> = Omit<
@@ -100,13 +101,24 @@ function ListImpl<ItemT>(
[], [],
) )
const onVisible = React.useCallback(() => { const [isVisible, setIsVisible] = React.useState(false)
onEndReached?.({
distanceFromEnd: onEndReachedThreshold || 0, React.useEffect(() => {
}) if (!isVisible) {
}, [onEndReachedThreshold, onEndReached]) return
}
function handleScroll() {
// TODO
}
window.addEventListener('scroll', handleScroll)
return () => window.removeEventListener('scroll', handleScroll)
}, [isVisible])
return ( return (
<Visibility
onVisibleChange={newIsVisible => {
setIsVisible(newIsVisible)
}}>
<ScrollView {...props} style={style} ref={nativeRef}> <ScrollView {...props} style={style} ref={nativeRef}>
<View <View
style={[ style={[
@@ -126,11 +138,21 @@ function ListImpl<ItemT>(
/> />
))} ))}
{onEndReached && ( {onEndReached && (
<Tail threshold={onEndReachedThreshold} onVisible={onVisible} /> <Visibility
threshold={onEndReachedThreshold}
onVisibleChange={isVisible => {
if (isVisible) {
onEndReached?.({
distanceFromEnd: onEndReachedThreshold || 0,
})
}
}}
/>
)} )}
{footer} {footer}
</View> </View>
</ScrollView> </ScrollView>
</Visibility>
) )
} }
@@ -159,38 +181,43 @@ let Row = function RowImpl<ItemT>({
} }
Row = React.memo(Row) Row = React.memo(Row)
let Tail = ({ let Visibility = ({
threshold = 0, threshold = 0,
onVisible, onVisibleChange,
children,
}: { }: {
threshold?: number | null | undefined threshold?: number | null | undefined
onVisible: () => void onVisibleChange: (isVisible: boolean) => void
children?: React.ReactNode
}): React.ReactNode => { }): React.ReactNode => {
const tailRef = React.useRef(null) const tailRef = React.useRef(null)
const isIntersecting = React.useRef(false)
React.useEffect(() => { const handleIntersection = useNonReactiveCallback(
const observer = new IntersectionObserver( (entries: IntersectionObserverEntry[]) => {
entries => {
entries.forEach(entry => { entries.forEach(entry => {
if (entry.isIntersecting) { if (entry.isIntersecting !== isIntersecting.current) {
onVisible() isIntersecting.current = entry.isIntersecting
onVisibleChange(entry.isIntersecting)
} }
}) })
}, },
{
rootMargin: (threshold || 0) * 100 + '%',
},
) )
React.useEffect(() => {
const observer = new IntersectionObserver(handleIntersection, {
rootMargin: (threshold || 0) * 100 + '%',
})
const tail: Element | null = tailRef.current! const tail: Element | null = tailRef.current!
observer.observe(tail) observer.observe(tail)
return () => { return () => {
observer.unobserve(tail) observer.unobserve(tail)
} }
}, [onVisible, threshold]) }, [handleIntersection, threshold])
return <View ref={tailRef} /> return <View ref={tailRef}>{children}</View>
} }
Tail = React.memo(Tail) Visibility = React.memo(Visibility)
export const List = memo(React.forwardRef(ListImpl)) as <ItemT>( export const List = memo(React.forwardRef(ListImpl)) as <ItemT>(
props: ListProps<ItemT> & {ref?: React.Ref<ListMethods>}, props: ListProps<ItemT> & {ref?: React.Ref<ListMethods>},
@@ -201,12 +228,6 @@ const styles = StyleSheet.create({
borderLeftWidth: 1, borderLeftWidth: 1,
borderRightWidth: 1, borderRightWidth: 1,
}, },
container: {
width: '100%',
maxWidth: 600,
marginLeft: 'auto',
marginRight: 'auto',
},
containerScroll: { containerScroll: {
width: '100%', width: '100%',
maxWidth: 600, maxWidth: 600,