Make scroll handling contextual (#2200)
* Add an intermediate List component * Fix type * Add onScrolledDownChange * Port pager to use onScrolledDownChange * Fix on mobile * Don't pass down onScroll (replacement TBD) * Remove resetMainScroll * Replace onMainScroll with MainScrollProvider * Hook ScrollProvider to pager * Fix the remaining special case * Optimize a bit * Enforce that onScroll cannot be passed * Keep value updated even if no handler * Also memo it
This commit is contained in:
parent
fa3ccafa80
commit
7fd7970237
26 changed files with 280 additions and 354 deletions
64
src/view/com/util/List.tsx
Normal file
64
src/view/com/util/List.tsx
Normal file
|
@ -0,0 +1,64 @@
|
|||
import React, {memo, startTransition} from 'react'
|
||||
import {FlatListProps} from 'react-native'
|
||||
import {FlatList_INTERNAL} from './Views'
|
||||
import {useScrollHandlers} from '#/lib/ScrollContext'
|
||||
import {runOnJS, useSharedValue} from 'react-native-reanimated'
|
||||
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
|
||||
|
||||
export type ListMethods = FlatList_INTERNAL
|
||||
export type ListProps<ItemT> = Omit<
|
||||
FlatListProps<ItemT>,
|
||||
'onScroll' // Use ScrollContext instead.
|
||||
> & {
|
||||
onScrolledDownChange?: (isScrolledDown: boolean) => void
|
||||
}
|
||||
export type ListRef = React.MutableRefObject<FlatList_INTERNAL | null>
|
||||
|
||||
const SCROLLED_DOWN_LIMIT = 200
|
||||
|
||||
function ListImpl<ItemT>(
|
||||
{onScrolledDownChange, ...props}: ListProps<ItemT>,
|
||||
ref: React.Ref<ListMethods>,
|
||||
) {
|
||||
const isScrolledDown = useSharedValue(false)
|
||||
const contextScrollHandlers = useScrollHandlers()
|
||||
|
||||
function handleScrolledDownChange(didScrollDown: boolean) {
|
||||
startTransition(() => {
|
||||
onScrolledDownChange?.(didScrollDown)
|
||||
})
|
||||
}
|
||||
|
||||
const scrollHandler = useAnimatedScrollHandler({
|
||||
onBeginDrag(e, ctx) {
|
||||
contextScrollHandlers.onBeginDrag?.(e, ctx)
|
||||
},
|
||||
onEndDrag(e, ctx) {
|
||||
contextScrollHandlers.onEndDrag?.(e, ctx)
|
||||
},
|
||||
onScroll(e, ctx) {
|
||||
contextScrollHandlers.onScroll?.(e, ctx)
|
||||
|
||||
const didScrollDown = e.contentOffset.y > SCROLLED_DOWN_LIMIT
|
||||
if (isScrolledDown.value !== didScrollDown) {
|
||||
isScrolledDown.value = didScrollDown
|
||||
if (onScrolledDownChange != null) {
|
||||
runOnJS(handleScrolledDownChange)(didScrollDown)
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
<FlatList_INTERNAL
|
||||
{...props}
|
||||
onScroll={scrollHandler}
|
||||
scrollEventThrottle={1}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const List = memo(React.forwardRef(ListImpl)) as <ItemT>(
|
||||
props: ListProps<ItemT> & {ref?: React.Ref<ListMethods>},
|
||||
) => React.ReactElement
|
Loading…
Add table
Add a link
Reference in a new issue