react-native-bottom-sheet: [v4] Adding index={-1} in certain devices blocks the view (Example device: Oneplus 5)

Bug

In certain devices like the OnePlus 5, adding an index={-1} is causing the entire screen to be non-functional, i.e, we’re unable to click anywhere on the screen. If we remove this prop, then everything seems to be working fine. But of course we need the BottomSheet to be in closed state initially, hence not adding this prop is not a solution. But this does work fine on other devices we’ve tested.

This issue is affecting many users in Production, since we’re using BottomSheet in many screens and the Users are unable to use those screens.

Environment info

Library Version
@gorhom/bottom-sheet 4.1.5
react-native 0.64.2
react-native-reanimated 2.2.4
react-native-gesture-handler 1.10.3

Steps To Reproduce

In certain devices only : Add an index={-1} in the BottomSheet is causing the entire screen to be non-functional. It is as though there’s an overlay on top of the screen which doesn’t let us access whatever is currently rendered.

Describe what you expected to happen:

It should not render the screen non-functional.

Reproducible sample code

import React, { useCallback } from 'react';
import { StyleSheet, Keyboard } from 'react-native';
import PropTypes from 'prop-types';
import { bottomSheetHeaderHandler } from 'colors';
import {
  heightPercentageToDP as hp,
  widthPercentageToDP as wp,
} from 'react-native-responsive-screen';

const renderBackdrop = props => (
  <BottomSheetBackdrop {...props} disappearsOnIndex={-1} appearsOnIndex={0} />
);

const BottomSheet = React.forwardRef((props, ref) => {
  const { children, onChange, ...restProps } = props;

  const handleChange = useCallback(index => {
    if (index === -1) {
      // When the BottomSheet is closed, dismiss any open Keyboard
      Keyboard.dismiss();
    }
    // Call the actual onChange handler passing in the index
    onChange?.(index);
  }, []);

  return (
    <BottomSheetGorhom
      index={-1}
      enablePanDownToClose
      backdropComponent={renderBackdrop}
      handleIndicatorStyle={styles.handleIndicatorStyle}
      ref={ref}
      onChange={handleChange}
      {...restProps}
    >
      {children}
    </BottomSheetGorhom>
  );
});

const styles = StyleSheet.create({
  handleIndicatorStyle: {
    width: wp('12.6%'),
    height: hp('0.65%'),
    borderRadius: 4,
    backgroundColor: bottomSheetHeaderHandler,
  },
});

BottomSheet.propTypes = {
  children: PropTypes.node,
  onChange: PropTypes.func,
};

export default BottomSheet;

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 12
  • Comments: 28 (2 by maintainers)

Most upvoted comments

I looked into this issue a bit myself on my Samsung S8+ device that is able to reproduce this issue.

In the BottomSheetBackDrop component you have the following code.

  //#region effects
  useAnimatedReaction(
    () => animatedIndex.value <= disappearsOnIndex,
    (shouldDisableTouchability, previous) => {
      if (shouldDisableTouchability === previous) {
        return;
      }
      runOnJS(handleContainerTouchability)(shouldDisableTouchability);
    },
    [disappearsOnIndex]
  );
  //#endregion

Which will call into handleContainerTouchability and set the pointerEvents prop.

  const handleContainerTouchability = useCallback(
    (shouldDisableTouchability: boolean) => {
      if (!containerRef.current) {
        return;
      }
      // @ts-ignore
      containerRef.current.setNativeProps({
        pointerEvents: shouldDisableTouchability ? 'none' : 'auto',
      });
    },
    []
  );

On my Samsung Galaxy S8+ the animatedIndex.value is reported as:

 // Samsung
 LOG  [ SM-G955F ] animatedIndex.value:  -1
 LOG  [ SM-G955F ] animatedIndex.value:  -0.9999999548556524
 // Simulator
 LOG  [ Android SDK built for x86 ] animatedIndex.value:  -1
 LOG  [ Android SDK built for x86 ] animatedIndex.value:  -1

As seen above, the animatedIndex.value <= disappearsOnIndex ( -0.9999999548556524 <= -1 ) will result in false, and the pointerEvents will be set to ‘none’, and the input will be blocked.

I encountered the same problem: on some Xiaomi or Samsung device the whole screen becomes freezed.

The only workaround i found is to set index={0} and provide a 0 snap point that has 0 height like the following:

const snapPoints = useMemo( () => ( [0, "60%", "80%"] ), [], );
<BottomSheet
      ref={ensureRef}
      index={Platform.OS === "android" ? 0 : -1}
      snapPoints={snapPoints}
      backdropComponent={BottomSheetBackdrop}
      backgroundComponent={() => <View style={styles.background} />}
      onChange={handleSheetChange}>
     {...children}
    </BottomSheet>

Based on what @vinkim said, This patch seems to work, but tested only for one snap point.

node_modules/@gorhom/bottom-sheet/src/components/bottomSheetBackdrop/BottomSheetBackdrop.tsx
@@ -95,14 +95,14 @@ const BottomSheetBackdropComponent = ({
 
   //#region effects
   useAnimatedReaction(
-    () => animatedIndex.value <= disappearsOnIndex,
+    () => !(animatedIndex.value >= appearsOnIndex),
     (shouldDisableTouchability, previous) => {
       if (shouldDisableTouchability === previous) {
         return;
       }
       runOnJS(handleContainerTouchability)(shouldDisableTouchability);
     },
-    [disappearsOnIndex]
+    [appearsOnIndex]
   );
   //#endregion
 

To everyone who has encountered this problem today, I suggest looking at your version of react-native-reanimated, this problem appears on version react-native-reanimated@^3 and disappears if you use version react-native-reanimated@^2

@whyamsx I’m using react-native-reanimated@~2.12.0 and still experiencing this issue

in my case it went like this

diff --git a/node_modules/@gorhom/bottom-sheet/src/components/bottomSheetBackdrop/BottomSheetBackdrop.tsx b/node_modules/@gorhom/bottom-sheet/src/components/bottomSheetBackdrop/BottomSheetBackdrop.tsx
index 2446c1d..778564c 100644
--- a/node_modules/@gorhom/bottom-sheet/src/components/bottomSheetBackdrop/BottomSheetBackdrop.tsx
+++ b/node_modules/@gorhom/bottom-sheet/src/components/bottomSheetBackdrop/BottomSheetBackdrop.tsx
@@ -104,7 +104,7 @@ const BottomSheetBackdropComponent = ({
 
   //#region effects
   useAnimatedReaction(
-    () => animatedIndex.value <= disappearsOnIndex,
+    () => Math.floor(animatedIndex.value) <= disappearsOnIndex,
     (shouldDisableTouchability, previous) => {
       if (shouldDisableTouchability === previous) {
         return;

@gorhom - Any update on adding this patch in your next release ? It’s affecting many devices we’ve tested on.