Add scroll handler
This commit is contained in:
@@ -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>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -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,37 +101,58 @@ 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 (
|
||||||
<ScrollView {...props} style={style} ref={nativeRef}>
|
<Visibility
|
||||||
<View
|
onVisibleChange={newIsVisible => {
|
||||||
style={[
|
setIsVisible(newIsVisible)
|
||||||
styles.contentContainer,
|
}}>
|
||||||
contentContainerStyle,
|
<ScrollView {...props} style={style} ref={nativeRef}>
|
||||||
desktopFixedHeight ? styles.minHeightViewport : null,
|
<View
|
||||||
pal.border,
|
style={[
|
||||||
]}>
|
styles.contentContainer,
|
||||||
{header}
|
contentContainerStyle,
|
||||||
{(data as Array<ItemT>).map((item, index) => (
|
desktopFixedHeight ? styles.minHeightViewport : null,
|
||||||
<Row<ItemT>
|
pal.border,
|
||||||
key={keyExtractor!(item, index)}
|
]}>
|
||||||
item={item}
|
{header}
|
||||||
index={index}
|
{(data as Array<ItemT>).map((item, index) => (
|
||||||
renderItem={renderItem}
|
<Row<ItemT>
|
||||||
extraData={extraData}
|
key={keyExtractor!(item, index)}
|
||||||
/>
|
item={item}
|
||||||
))}
|
index={index}
|
||||||
{onEndReached && (
|
renderItem={renderItem}
|
||||||
<Tail threshold={onEndReachedThreshold} onVisible={onVisible} />
|
extraData={extraData}
|
||||||
)}
|
/>
|
||||||
{footer}
|
))}
|
||||||
</View>
|
{onEndReached && (
|
||||||
</ScrollView>
|
<Visibility
|
||||||
|
threshold={onEndReachedThreshold}
|
||||||
|
onVisibleChange={isVisible => {
|
||||||
|
if (isVisible) {
|
||||||
|
onEndReached?.({
|
||||||
|
distanceFromEnd: onEndReachedThreshold || 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{footer}
|
||||||
|
</View>
|
||||||
|
</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)
|
||||||
|
|
||||||
|
const handleIntersection = useNonReactiveCallback(
|
||||||
|
(entries: IntersectionObserverEntry[]) => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
if (entry.isIntersecting !== isIntersecting.current) {
|
||||||
|
isIntersecting.current = entry.isIntersecting
|
||||||
|
onVisibleChange(entry.isIntersecting)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const observer = new IntersectionObserver(
|
const observer = new IntersectionObserver(handleIntersection, {
|
||||||
entries => {
|
rootMargin: (threshold || 0) * 100 + '%',
|
||||||
entries.forEach(entry => {
|
})
|
||||||
if (entry.isIntersecting) {
|
|
||||||
onVisible()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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,
|
||||||
|
|||||||
Reference in New Issue
Block a user