Skip to content

Commit 1f3c07d

Browse files
committed
fix: set native props not available on web
1 parent cef693c commit 1f3c07d

File tree

5 files changed

+65
-40
lines changed

5 files changed

+65
-40
lines changed

src/components/NestedReorderableList.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ const NestedReorderableListWithRef = <T,>(
1616
scrollViewPageY,
1717
scrollViewHeightY,
1818
scrollViewScrollEnabledProp,
19-
scrollViewCurrentScrollEnabled,
2019
outerScrollGesture,
20+
setScrollViewForceDisableScroll,
2121
} = useContext(ScrollViewContainerContext);
2222

2323
return (
@@ -30,7 +30,7 @@ const NestedReorderableListWithRef = <T,>(
3030
scrollViewHeightY={scrollViewHeightY}
3131
outerScrollGesture={outerScrollGesture}
3232
scrollViewScrollEnabledProp={scrollViewScrollEnabledProp}
33-
scrollViewCurrentScrollEnabled={scrollViewCurrentScrollEnabled}
33+
setScrollViewForceDisableScroll={setScrollViewForceDisableScroll}
3434
scrollable={scrollable}
3535
nestedScrollEnabled
3636
/>

src/components/ReorderableList.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const ReorderableListWithRef = <T,>(
1717
scrollViewHeightY={undefined}
1818
outerScrollGesture={undefined}
1919
scrollViewScrollEnabledProp={undefined}
20-
scrollViewCurrentScrollEnabled={undefined}
20+
setScrollViewForceDisableScroll={undefined}
2121
scrollable
2222
/>
2323
);

src/components/ReorderableListCore.tsx

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
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';
211
import {
312
CellRendererProps,
413
FlatList,
@@ -53,12 +62,14 @@ const AnimatedFlatList = Animated.createAnimatedComponent(
5362

5463
interface 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>

src/components/ScrollViewContainer.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {forwardRef, useCallback, useMemo} from 'react';
1+
import React, {forwardRef, useCallback, useMemo, useState} from 'react';
22
import {LayoutChangeEvent, ScrollView} from 'react-native';
33

44
import {Gesture, GestureDetector} from 'react-native-gesture-handler';
@@ -21,8 +21,9 @@ const ScrollViewContainerWithRef = (
2121
) => {
2222
const scrollEnabled = rest.scrollEnabled ?? true;
2323

24+
const [scrollViewForceDisableScroll, setScrollViewForceDisableScroll] =
25+
useState(false);
2426
const scrollViewScrollEnabledProp = usePropAsSharedValue(scrollEnabled);
25-
const scrollViewCurrentScrollEnabled = useSharedValue(scrollEnabled);
2627
const scrollViewContainerRef = useAnimatedRef<Animated.ScrollView>();
2728
const scrollViewScrollOffsetY = useSharedValue(0);
2829
const scrollViewPageY = useSharedValue(0);
@@ -62,17 +63,17 @@ const ScrollViewContainerWithRef = (
6263
scrollViewHeightY,
6364
scrollViewScrollOffsetY,
6465
scrollViewScrollEnabledProp,
65-
scrollViewCurrentScrollEnabled,
6666
outerScrollGesture,
67+
setScrollViewForceDisableScroll,
6768
}),
6869
[
6970
scrollViewContainerRef,
7071
scrollViewPageY,
7172
scrollViewHeightY,
7273
scrollViewScrollOffsetY,
7374
scrollViewScrollEnabledProp,
74-
scrollViewCurrentScrollEnabled,
7575
outerScrollGesture,
76+
setScrollViewForceDisableScroll,
7677
],
7778
);
7879

@@ -103,6 +104,8 @@ const ScrollViewContainerWithRef = (
103104
ref={handleRef}
104105
onScroll={composedScrollHandler}
105106
onLayout={handleLayout}
107+
// We force disable scroll or let the component prop control it.
108+
scrollEnabled={scrollViewForceDisableScroll ? false : scrollEnabled}
106109
/>
107110
</GestureDetector>
108111
</ScrollViewContainerContext.Provider>

src/contexts/ScrollViewContainerContext.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, {Dispatch, SetStateAction} from 'react';
22
import {ScrollView} from 'react-native';
33

44
import {NativeGesture} from 'react-native-gesture-handler';
@@ -10,8 +10,8 @@ interface ScrollViewContainerContextData {
1010
scrollViewHeightY: SharedValue<number>;
1111
scrollViewScrollOffsetY: SharedValue<number>;
1212
scrollViewScrollEnabledProp: SharedValue<boolean>;
13-
scrollViewCurrentScrollEnabled: SharedValue<boolean>;
1413
outerScrollGesture: NativeGesture;
14+
setScrollViewForceDisableScroll: Dispatch<SetStateAction<boolean>>;
1515
}
1616

1717
export const ScrollViewContainerContext = React.createContext<

0 commit comments

Comments
 (0)