Track pager state change in a worklet

This commit is contained in:
Dan Abramov
2024-11-27 03:40:21 +00:00
parent dc89c75e18
commit 7732a7b8f3
2 changed files with 26 additions and 18 deletions
+25 -18
View File
@@ -1,8 +1,9 @@
import React, {forwardRef} from 'react' import React, {forwardRef} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import PagerView, { import PagerView, {
PagerViewOnPageScrollEventData,
PagerViewOnPageSelectedEvent, PagerViewOnPageSelectedEvent,
PageScrollStateChangedNativeEvent, PageScrollStateChangedNativeEventData,
} from 'react-native-pager-view' } from 'react-native-pager-view'
import Animated, { import Animated, {
useEvent, useEvent,
@@ -43,7 +44,7 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
children, children,
initialPage = 0, initialPage = 0,
renderTabBar, renderTabBar,
onPageScrollStateChanged, onPageScrollStateChanged: parentOnPageScrollStateChanged,
onPageSelected, onPageSelected,
testID, testID,
}: React.PropsWithChildren<Props>, }: React.PropsWithChildren<Props>,
@@ -67,13 +68,6 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
[setSelectedPage, onPageSelected], [setSelectedPage, onPageSelected],
) )
const handlePageScrollStateChanged = React.useCallback(
(e: PageScrollStateChangedNativeEvent) => {
onPageScrollStateChanged?.(e.nativeEvent.pageScrollState)
},
[onPageScrollStateChanged],
)
const onTabBarSelect = React.useCallback( const onTabBarSelect = React.useCallback(
(index: number) => { (index: number) => {
pagerView.current?.setPage(index) pagerView.current?.setPage(index)
@@ -81,15 +75,19 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
[pagerView], [pagerView],
) )
const handlePageScroll = usePageScrollHandler( const handlePageScroll = usePagerHandlers(
{ {
onPageScroll(e: any) { onPageScroll(e: PagerViewOnPageScrollEventData) {
'worklet' 'worklet'
const progress = e.offset + e.position const progress = e.offset + e.position
dragProgress.value = progress dragProgress.value = progress
}, },
onPageScrollStateChanged(e: PageScrollStateChangedNativeEventData) {
'worklet'
parentOnPageScrollStateChanged?.(e.pageScrollState)
},
}, },
[], [parentOnPageScrollStateChanged],
) )
return ( return (
@@ -102,7 +100,6 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
ref={pagerView} ref={pagerView}
style={[a.flex_1]} style={[a.flex_1]}
initialPage={initialPage} initialPage={initialPage}
onPageScrollStateChanged={handlePageScrollStateChanged}
onPageSelected={onPageSelectedInner} onPageSelected={onPageSelectedInner}
onPageScroll={handlePageScroll}> onPageScroll={handlePageScroll}>
{children} {children}
@@ -112,15 +109,25 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
}, },
) )
function usePageScrollHandler(handlers: any, dependencies: any): any { function usePagerHandlers(
const {context, doDependenciesDiffer} = useHandler(handlers, dependencies) handlers: {
const subscribeForEvents = ['onPageScroll'] onPageScroll: (e: PagerViewOnPageScrollEventData) => void
const {onPageScroll} = handlers onPageScrollStateChanged: (e: PageScrollStateChangedNativeEventData) => void
},
dependencies: unknown[],
) {
const {doDependenciesDiffer} = useHandler(handlers as any, dependencies)
const subscribeForEvents = ['onPageScroll', 'onPageScrollStateChanged']
return useEvent( return useEvent(
event => { event => {
'worklet' 'worklet'
const {onPageScroll, onPageScrollStateChanged} = handlers
if (event.eventName.endsWith('onPageScroll')) { if (event.eventName.endsWith('onPageScroll')) {
onPageScroll?.(event, context) onPageScroll(event as any as PagerViewOnPageScrollEventData)
} else if (event.eventName.endsWith('onPageScrollStateChanged')) {
onPageScrollStateChanged(
event as any as PageScrollStateChangedNativeEventData,
)
} }
}, },
subscribeForEvents, subscribeForEvents,
+1
View File
@@ -173,6 +173,7 @@ function HomeScreenReady({
const onPageScrollStateChanged = React.useCallback( const onPageScrollStateChanged = React.useCallback(
(state: 'idle' | 'dragging' | 'settling') => { (state: 'idle' | 'dragging' | 'settling') => {
'worklet'
if (state === 'dragging') { if (state === 'dragging') {
setMinimalShellMode(false) setMinimalShellMode(false)
} }