1- import React , { useCallback , useEffect , useMemo , useRef , useState } from 'react' ;
1+ import React , {
2+ Dispatch ,
3+ RefObject ,
4+ SetStateAction ,
5+ useCallback ,
6+ useEffect ,
7+ useMemo ,
8+ useRef ,
9+ useState ,
10+ } from 'react' ;
211import {
312 CellRendererProps ,
413 FlatList ,
@@ -53,12 +62,14 @@ const AnimatedFlatList = Animated.createAnimatedComponent(
5362
5463interface ReorderableListCoreProps < T > extends ReorderableListProps < T > {
5564 // Not optional but undefined to force passing the prop.
56- scrollViewContainerRef : React . RefObject < ScrollView > | undefined ;
65+ scrollViewContainerRef : RefObject < ScrollView > | undefined ;
5766 scrollViewPageY : SharedValue < number > | undefined ;
5867 scrollViewHeightY : SharedValue < number > | undefined ;
5968 scrollViewScrollOffsetY : SharedValue < number > | undefined ;
6069 scrollViewScrollEnabledProp : SharedValue < boolean > | undefined ;
61- scrollViewCurrentScrollEnabled : SharedValue < boolean > | undefined ;
70+ setScrollViewForceDisableScroll :
71+ | Dispatch < SetStateAction < boolean > >
72+ | undefined ;
6273 outerScrollGesture : NativeGesture | undefined ;
6374 scrollable : boolean | undefined ;
6475}
@@ -82,7 +93,7 @@ const ReorderableListCore = <T,>(
8293 scrollViewHeightY,
8394 scrollViewScrollOffsetY,
8495 scrollViewScrollEnabledProp,
85- scrollViewCurrentScrollEnabled ,
96+ setScrollViewForceDisableScroll ,
8697 scrollable,
8798 outerScrollGesture,
8899 cellAnimations,
@@ -105,7 +116,10 @@ const ReorderableListCore = <T,>(
105116 const [ activeIndex , setActiveIndex ] = useState ( - 1 ) ;
106117 const prevItemCount = useRef ( data . length ) ;
107118
119+ const [ forceDisableScroll , setForceDisableScroll ] = useState ( false ) ;
120+ const scrollEnabledProp = usePropAsSharedValue ( scrollEnabled ) ;
108121 const currentScrollEnabled = useSharedValue ( scrollEnabled ) ;
122+
109123 const gestureState = useSharedValue < State > ( State . UNDETERMINED ) ;
110124 const currentY = useSharedValue ( 0 ) ;
111125 const currentTranslationY = useSharedValue ( 0 ) ;
@@ -149,7 +163,6 @@ const ReorderableListCore = <T,>(
149163 const keyExtractorPropRef = useRef ( keyExtractor ) ;
150164 keyExtractorPropRef . current = keyExtractor ;
151165
152- const scrollEnabledProp = usePropAsSharedValue ( scrollEnabled ) ;
153166 const animationDurationProp = usePropAsSharedValue ( animationDuration ) ;
154167 const autoscrollActivationDeltaProp = usePropAsSharedValue (
155168 autoscrollActivationDelta ,
@@ -387,32 +400,38 @@ const ReorderableListCore = <T,>(
387400
388401 const setScrollEnabled = useCallback (
389402 ( enabled : boolean ) => {
390- // When re-enabling the scroll of the flatlist we check whether its prop is set to true.
391- if ( ( enabled && scrollEnabledProp . value ) || ! enabled ) {
392- currentScrollEnabled . value = enabled ;
393- flatListRef . current ?. setNativeProps ( { scrollEnabled : enabled } ) ;
394- }
403+ currentScrollEnabled . value = enabled ;
395404
396- if (
397- scrollViewContainerRef &&
398- scrollViewScrollEnabledProp &&
399- scrollViewCurrentScrollEnabled &&
400- // When re-enabling the scroll of the container we check whether its prop is set to true.
401- ( ( enabled && scrollViewScrollEnabledProp ?. value ) || ! enabled )
402- ) {
403- scrollViewCurrentScrollEnabled . value = enabled ;
404- scrollViewContainerRef . current ?. setNativeProps ( {
405- scrollEnabled : enabled ,
406- } ) ;
405+ // IMPORTANT:
406+ // On web setNativeProps API is not available, so disabling scroll is controlled by a state.
407+ // On Android/iOS we can keep using setNativeProps which performs better and doesn't require re-renders.
408+ if ( Platform . OS === 'web' ) {
409+ setForceDisableScroll ( ! enabled ) ;
410+
411+ if ( setScrollViewForceDisableScroll ) {
412+ setScrollViewForceDisableScroll ( ! enabled ) ;
413+ }
414+ } else {
415+ if ( ! enabled || scrollEnabledProp . value ) {
416+ // We disable the scroll or when re-enabling the scroll of the container we set it back to the current prop value.
417+ flatListRef . current ?. setNativeProps ( { scrollEnabled : enabled } ) ;
418+ }
419+
420+ if ( ! enabled || scrollViewScrollEnabledProp ?. value ) {
421+ // We disable the scroll or when re-enabling the scroll of the container we set it back to the current prop value.
422+ scrollViewContainerRef ?. current ?. setNativeProps ( {
423+ scrollEnabled : enabled ,
424+ } ) ;
425+ }
407426 }
408427 } ,
409428 [
429+ currentScrollEnabled ,
410430 flatListRef ,
411431 scrollEnabledProp ,
412- currentScrollEnabled ,
413- scrollViewScrollEnabledProp ,
414- scrollViewCurrentScrollEnabled ,
415432 scrollViewContainerRef ,
433+ scrollViewScrollEnabledProp ,
434+ setScrollViewForceDisableScroll ,
416435 ] ,
417436 ) ;
418437
@@ -855,9 +874,9 @@ const ReorderableListCore = <T,>(
855874 const handleScroll = useAnimatedScrollHandler ( e => {
856875 flatListScrollOffsetY . value = e . contentOffset . y ;
857876
858- // checking if the list is not scrollable instead of the scrolling state
859- // fixes a bug on iOS where the item is shifted after autoscrolling and then
860- // moving away from autoscroll area
877+ // Checking if the list is not scrollable instead of the scrolling state.
878+ // Fixes a bug on iOS where the item is shifted after autoscrolling and then
879+ // moving away from the area.
861880 if ( ! currentScrollEnabled . value ) {
862881 dragScrollTranslationY . value =
863882 flatListScrollOffsetY . value - dragInitialScrollOffsetY . value ;
@@ -881,10 +900,11 @@ const ReorderableListCore = <T,>(
881900 useAnimatedReaction (
882901 ( ) => scrollViewScrollOffsetY ?. value ,
883902 value => {
884- if ( value && scrollViewCurrentScrollEnabled ) {
885- // checking if the list is not scrollable instead of the scrolling state
886- // fixes a bug on iOS where the item is shifted after autoscrolling and moving away from the area
887- if ( ! scrollViewCurrentScrollEnabled . value ) {
903+ if ( value ) {
904+ // Checking if the list is not scrollable instead of the scrolling state.
905+ // Fixes a bug on iOS where the item is shifted after autoscrolling and then
906+ // moving away from the area.
907+ if ( ! currentScrollEnabled . value ) {
888908 scrollViewDragScrollTranslationY . value =
889909 value - scrollViewDragInitialScrollOffsetY . value ;
890910 }
@@ -1048,6 +1068,8 @@ const ReorderableListCore = <T,>(
10481068 horizontal = { false }
10491069 removeClippedSubviews = { false }
10501070 numColumns = { 1 }
1071+ // We force disable scroll or let the component prop control it.
1072+ scrollEnabled = { forceDisableScroll ? false : scrollEnabled }
10511073 />
10521074 </ GestureDetector >
10531075 </ ReorderableListContext . Provider >
0 commit comments