Port pager to use onScrolledDownChange

This commit is contained in:
Dan Abramov
2023-12-13 04:18:54 +00:00
parent b4de3dda7d
commit b93ab428c3
5 changed files with 23 additions and 66 deletions
+3
View File
@@ -35,6 +35,7 @@ export function ListMembers({
style, style,
scrollElRef, scrollElRef,
onScroll, onScroll,
onScrolledDownChange,
onPressTryAgain, onPressTryAgain,
renderHeader, renderHeader,
renderEmptyState, renderEmptyState,
@@ -47,6 +48,7 @@ export function ListMembers({
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
scrollElRef?: ListRef scrollElRef?: ListRef
onScroll: OnScrollHandler onScroll: OnScrollHandler
onScrolledDownChange: (isScrolledDown: boolean) => void
onPressTryAgain?: () => void onPressTryAgain?: () => void
renderHeader: () => JSX.Element renderHeader: () => JSX.Element
renderEmptyState: () => JSX.Element renderEmptyState: () => JSX.Element
@@ -234,6 +236,7 @@ export function ListMembers({
}} }}
style={{paddingTop: headerOffset}} style={{paddingTop: headerOffset}}
onScroll={scrollHandler} onScroll={scrollHandler}
onScrolledDownChange={onScrolledDownChange}
onEndReached={onEndReached} onEndReached={onEndReached}
onEndReachedThreshold={0.6} onEndReachedThreshold={0.6}
scrollEventThrottle={scrollEventThrottle} scrollEventThrottle={scrollEventThrottle}
-16
View File
@@ -23,13 +23,10 @@ import {OnScrollHandler} from 'lib/hooks/useOnMainScroll'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
import {ListMethods} from '../util/List' import {ListMethods} from '../util/List'
const SCROLLED_DOWN_LIMIT = 200
export interface PagerWithHeaderChildParams { export interface PagerWithHeaderChildParams {
headerHeight: number headerHeight: number
isFocused: boolean isFocused: boolean
onScroll: OnScrollHandler onScroll: OnScrollHandler
isScrolledDown: boolean
scrollElRef: React.MutableRefObject<ListMethods | ScrollView | null> scrollElRef: React.MutableRefObject<ListMethods | ScrollView | null>
} }
@@ -62,7 +59,6 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
const [currentPage, setCurrentPage] = React.useState(0) const [currentPage, setCurrentPage] = React.useState(0)
const [tabBarHeight, setTabBarHeight] = React.useState(0) const [tabBarHeight, setTabBarHeight] = React.useState(0)
const [headerOnlyHeight, setHeaderOnlyHeight] = React.useState(0) const [headerOnlyHeight, setHeaderOnlyHeight] = React.useState(0)
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
const scrollY = useSharedValue(0) const scrollY = useSharedValue(0)
const headerHeight = headerOnlyHeight + tabBarHeight const headerHeight = headerOnlyHeight + tabBarHeight
@@ -155,15 +151,7 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
if (!throttleTimeout.current) { if (!throttleTimeout.current) {
throttleTimeout.current = setTimeout(() => { throttleTimeout.current = setTimeout(() => {
throttleTimeout.current = null throttleTimeout.current = null
runOnUI(adjustScrollForOtherPages)() runOnUI(adjustScrollForOtherPages)()
const nextIsScrolledDown = scrollY.value > SCROLLED_DOWN_LIMIT
if (isScrolledDown !== nextIsScrolledDown) {
React.startTransition(() => {
setIsScrolledDown(nextIsScrolledDown)
})
}
}, 80 /* Sync often enough you're unlikely to catch it unsynced */) }, 80 /* Sync often enough you're unlikely to catch it unsynced */)
} }
}) })
@@ -211,7 +199,6 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
index={i} index={i}
isReady={isReady} isReady={isReady}
isFocused={i === currentPage} isFocused={i === currentPage}
isScrolledDown={isScrolledDown}
onScrollWorklet={i === currentPage ? onScrollWorklet : noop} onScrollWorklet={i === currentPage ? onScrollWorklet : noop}
registerRef={registerRef} registerRef={registerRef}
renderTab={child} renderTab={child}
@@ -293,7 +280,6 @@ function PagerItem({
index, index,
isReady, isReady,
isFocused, isFocused,
isScrolledDown,
onScrollWorklet, onScrollWorklet,
renderTab, renderTab,
registerRef, registerRef,
@@ -302,7 +288,6 @@ function PagerItem({
index: number index: number
isFocused: boolean isFocused: boolean
isReady: boolean isReady: boolean
isScrolledDown: boolean
registerRef: (scrollRef: AnimatedRef<any> | null, atIndex: number) => void registerRef: (scrollRef: AnimatedRef<any> | null, atIndex: number) => void
onScrollWorklet: (e: NativeScrollEvent) => void onScrollWorklet: (e: NativeScrollEvent) => void
renderTab: ((props: PagerWithHeaderChildParams) => JSX.Element) | null renderTab: ((props: PagerWithHeaderChildParams) => JSX.Element) | null
@@ -328,7 +313,6 @@ function PagerItem({
return renderTab({ return renderTab({
headerHeight, headerHeight,
isFocused, isFocused,
isScrolledDown,
onScroll: scrollHandler, onScroll: scrollHandler,
scrollElRef: scrollElRef as React.MutableRefObject< scrollElRef: scrollElRef as React.MutableRefObject<
ListMethods | ScrollView | null ListMethods | ScrollView | null
+7 -30
View File
@@ -278,65 +278,49 @@ function ProfileScreenLoaded({
onPageSelected={onPageSelected} onPageSelected={onPageSelected}
onCurrentPageSelected={onCurrentPageSelected} onCurrentPageSelected={onCurrentPageSelected}
renderHeader={renderHeader}> renderHeader={renderHeader}>
{({onScroll, headerHeight, isFocused, isScrolledDown, scrollElRef}) => ( {({onScroll, headerHeight, isFocused, scrollElRef}) => (
<FeedSection <FeedSection
ref={postsSectionRef} ref={postsSectionRef}
feed={`author|${profile.did}|posts_and_author_threads`} feed={`author|${profile.did}|posts_and_author_threads`}
onScroll={onScroll} onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isFocused={isFocused} isFocused={isFocused}
isScrolledDown={isScrolledDown}
scrollElRef={scrollElRef as ListRef} scrollElRef={scrollElRef as ListRef}
ignoreFilterFor={profile.did} ignoreFilterFor={profile.did}
/> />
)} )}
{showRepliesTab {showRepliesTab
? ({ ? ({onScroll, headerHeight, isFocused, scrollElRef}) => (
onScroll,
headerHeight,
isFocused,
isScrolledDown,
scrollElRef,
}) => (
<FeedSection <FeedSection
ref={repliesSectionRef} ref={repliesSectionRef}
feed={`author|${profile.did}|posts_with_replies`} feed={`author|${profile.did}|posts_with_replies`}
onScroll={onScroll} onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isFocused={isFocused} isFocused={isFocused}
isScrolledDown={isScrolledDown}
scrollElRef={scrollElRef as ListRef} scrollElRef={scrollElRef as ListRef}
ignoreFilterFor={profile.did} ignoreFilterFor={profile.did}
/> />
) )
: null} : null}
{({onScroll, headerHeight, isFocused, isScrolledDown, scrollElRef}) => ( {({onScroll, headerHeight, isFocused, scrollElRef}) => (
<FeedSection <FeedSection
ref={mediaSectionRef} ref={mediaSectionRef}
feed={`author|${profile.did}|posts_with_media`} feed={`author|${profile.did}|posts_with_media`}
onScroll={onScroll} onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isFocused={isFocused} isFocused={isFocused}
isScrolledDown={isScrolledDown}
scrollElRef={scrollElRef as ListRef} scrollElRef={scrollElRef as ListRef}
ignoreFilterFor={profile.did} ignoreFilterFor={profile.did}
/> />
)} )}
{showLikesTab {showLikesTab
? ({ ? ({onScroll, headerHeight, isFocused, scrollElRef}) => (
onScroll,
headerHeight,
isFocused,
isScrolledDown,
scrollElRef,
}) => (
<FeedSection <FeedSection
ref={likesSectionRef} ref={likesSectionRef}
feed={`likes|${profile.did}`} feed={`likes|${profile.did}`}
onScroll={onScroll} onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isFocused={isFocused} isFocused={isFocused}
isScrolledDown={isScrolledDown}
scrollElRef={scrollElRef as ListRef} scrollElRef={scrollElRef as ListRef}
ignoreFilterFor={profile.did} ignoreFilterFor={profile.did}
/> />
@@ -388,25 +372,17 @@ interface FeedSectionProps {
onScroll: OnScrollHandler onScroll: OnScrollHandler
headerHeight: number headerHeight: number
isFocused: boolean isFocused: boolean
isScrolledDown: boolean
scrollElRef: ListRef scrollElRef: ListRef
ignoreFilterFor?: string ignoreFilterFor?: string
} }
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>( const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
function FeedSectionImpl( function FeedSectionImpl(
{ {feed, onScroll, headerHeight, isFocused, scrollElRef, ignoreFilterFor},
feed,
onScroll,
headerHeight,
isFocused,
isScrolledDown,
scrollElRef,
ignoreFilterFor,
},
ref, ref,
) { ) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const [hasNew, setHasNew] = React.useState(false) const [hasNew, setHasNew] = React.useState(false)
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
const onScrollToTop = React.useCallback(() => { const onScrollToTop = React.useCallback(() => {
scrollElRef.current?.scrollToOffset({ scrollElRef.current?.scrollToOffset({
@@ -433,6 +409,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
scrollElRef={scrollElRef} scrollElRef={scrollElRef}
onHasNew={setHasNew} onHasNew={setHasNew}
onScroll={onScroll} onScroll={onScroll}
onScrolledDownChange={setIsScrolledDown}
scrollEventThrottle={1} scrollEventThrottle={1}
renderEmptyState={renderPostsEmpty} renderEmptyState={renderPostsEmpty}
headerOffset={headerHeight} headerOffset={headerHeight}
+4 -4
View File
@@ -398,14 +398,13 @@ export function ProfileFeedScreenInner({
isHeaderReady={true} isHeaderReady={true}
renderHeader={renderHeader} renderHeader={renderHeader}
onCurrentPageSelected={onCurrentPageSelected}> onCurrentPageSelected={onCurrentPageSelected}>
{({onScroll, headerHeight, isScrolledDown, scrollElRef, isFocused}) => {({onScroll, headerHeight, scrollElRef, isFocused}) =>
isPublicResponse?.isPublic ? ( isPublicResponse?.isPublic ? (
<FeedSection <FeedSection
ref={feedSectionRef} ref={feedSectionRef}
feed={`feedgen|${feedInfo.uri}`} feed={`feedgen|${feedInfo.uri}`}
onScroll={onScroll} onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isScrolledDown={isScrolledDown}
scrollElRef={scrollElRef as ListRef} scrollElRef={scrollElRef as ListRef}
isFocused={isFocused} isFocused={isFocused}
/> />
@@ -492,16 +491,16 @@ interface FeedSectionProps {
feed: FeedDescriptor feed: FeedDescriptor
onScroll: OnScrollHandler onScroll: OnScrollHandler
headerHeight: number headerHeight: number
isScrolledDown: boolean
scrollElRef: ListRef scrollElRef: ListRef
isFocused: boolean isFocused: boolean
} }
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>( const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
function FeedSectionImpl( function FeedSectionImpl(
{feed, onScroll, headerHeight, isScrolledDown, scrollElRef, isFocused}, {feed, onScroll, headerHeight, scrollElRef, isFocused},
ref, ref,
) { ) {
const [hasNew, setHasNew] = React.useState(false) const [hasNew, setHasNew] = React.useState(false)
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
const queryClient = useQueryClient() const queryClient = useQueryClient()
const onScrollToTop = useCallback(() => { const onScrollToTop = useCallback(() => {
@@ -530,6 +529,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
scrollElRef={scrollElRef} scrollElRef={scrollElRef}
onHasNew={setHasNew} onHasNew={setHasNew}
onScroll={onScroll} onScroll={onScroll}
onScrolledDownChange={setIsScrolledDown}
scrollEventThrottle={5} scrollEventThrottle={5}
renderEmptyState={renderPostsEmpty} renderEmptyState={renderPostsEmpty}
headerOffset={headerHeight} headerOffset={headerHeight}
+9 -16
View File
@@ -160,24 +160,17 @@ function ProfileListScreenLoaded({
isHeaderReady={true} isHeaderReady={true}
renderHeader={renderHeader} renderHeader={renderHeader}
onCurrentPageSelected={onCurrentPageSelected}> onCurrentPageSelected={onCurrentPageSelected}>
{({ {({onScroll, headerHeight, scrollElRef, isFocused}) => (
onScroll,
headerHeight,
isScrolledDown,
scrollElRef,
isFocused,
}) => (
<FeedSection <FeedSection
ref={feedSectionRef} ref={feedSectionRef}
feed={`list|${uri}`} feed={`list|${uri}`}
scrollElRef={scrollElRef as ListRef} scrollElRef={scrollElRef as ListRef}
onScroll={onScroll} onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isScrolledDown={isScrolledDown}
isFocused={isFocused} isFocused={isFocused}
/> />
)} )}
{({onScroll, headerHeight, isScrolledDown, scrollElRef}) => ( {({onScroll, headerHeight, scrollElRef}) => (
<AboutSection <AboutSection
ref={aboutSectionRef} ref={aboutSectionRef}
scrollElRef={scrollElRef as ListRef} scrollElRef={scrollElRef as ListRef}
@@ -185,7 +178,6 @@ function ProfileListScreenLoaded({
onPressAddUser={onPressAddUser} onPressAddUser={onPressAddUser}
onScroll={onScroll} onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isScrolledDown={isScrolledDown}
/> />
)} )}
</PagerWithHeader> </PagerWithHeader>
@@ -212,14 +204,13 @@ function ProfileListScreenLoaded({
items={SECTION_TITLES_MOD} items={SECTION_TITLES_MOD}
isHeaderReady={true} isHeaderReady={true}
renderHeader={renderHeader}> renderHeader={renderHeader}>
{({onScroll, headerHeight, isScrolledDown, scrollElRef}) => ( {({onScroll, headerHeight, scrollElRef}) => (
<AboutSection <AboutSection
list={list} list={list}
scrollElRef={scrollElRef as ListRef} scrollElRef={scrollElRef as ListRef}
onPressAddUser={onPressAddUser} onPressAddUser={onPressAddUser}
onScroll={onScroll} onScroll={onScroll}
headerHeight={headerHeight} headerHeight={headerHeight}
isScrolledDown={isScrolledDown}
/> />
)} )}
</PagerWithHeader> </PagerWithHeader>
@@ -606,17 +597,17 @@ interface FeedSectionProps {
feed: FeedDescriptor feed: FeedDescriptor
onScroll: OnScrollHandler onScroll: OnScrollHandler
headerHeight: number headerHeight: number
isScrolledDown: boolean
scrollElRef: ListRef scrollElRef: ListRef
isFocused: boolean isFocused: boolean
} }
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>( const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
function FeedSectionImpl( function FeedSectionImpl(
{feed, scrollElRef, onScroll, headerHeight, isScrolledDown, isFocused}, {feed, scrollElRef, onScroll, headerHeight, isFocused},
ref, ref,
) { ) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const [hasNew, setHasNew] = React.useState(false) const [hasNew, setHasNew] = React.useState(false)
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
const onScrollToTop = useCallback(() => { const onScrollToTop = useCallback(() => {
scrollElRef.current?.scrollToOffset({ scrollElRef.current?.scrollToOffset({
@@ -644,6 +635,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
scrollElRef={scrollElRef} scrollElRef={scrollElRef}
onHasNew={setHasNew} onHasNew={setHasNew}
onScroll={onScroll} onScroll={onScroll}
onScrolledDownChange={setIsScrolledDown}
scrollEventThrottle={1} scrollEventThrottle={1}
renderEmptyState={renderPostsEmpty} renderEmptyState={renderPostsEmpty}
headerOffset={headerHeight} headerOffset={headerHeight}
@@ -665,18 +657,18 @@ interface AboutSectionProps {
onPressAddUser: () => void onPressAddUser: () => void
onScroll: OnScrollHandler onScroll: OnScrollHandler
headerHeight: number headerHeight: number
isScrolledDown: boolean
scrollElRef: ListRef scrollElRef: ListRef
} }
const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>( const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
function AboutSectionImpl( function AboutSectionImpl(
{list, onPressAddUser, onScroll, headerHeight, isScrolledDown, scrollElRef}, {list, onPressAddUser, onScroll, headerHeight, scrollElRef},
ref, ref,
) { ) {
const pal = usePalette('default') const pal = usePalette('default')
const {_} = useLingui() const {_} = useLingui()
const {isMobile} = useWebMediaQueries() const {isMobile} = useWebMediaQueries()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
const isCurateList = list.purpose === 'app.bsky.graph.defs#curatelist' const isCurateList = list.purpose === 'app.bsky.graph.defs#curatelist'
const isOwner = list.creator.did === currentAccount?.did const isOwner = list.creator.did === currentAccount?.did
@@ -807,6 +799,7 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
renderEmptyState={renderEmptyState} renderEmptyState={renderEmptyState}
headerOffset={headerHeight} headerOffset={headerHeight}
onScroll={onScroll} onScroll={onScroll}
onScrolledDownChange={setIsScrolledDown}
scrollEventThrottle={1} scrollEventThrottle={1}
/> />
{isScrolledDown && ( {isScrolledDown && (