skip to Main Content

I have been developing an app on React-Native. The problem I am facing is that I have implemented gorhoms bottom sheet in my React-Native app and that should work when I click on the current location. This bottom sheet is working on Android, like it opens but it doesn’t work on the iOS because there is something wrong with the navigation router. When I permanently remove the initial screens only that renders on my iphone. I don’t know what the issue is.

I have shared here the code for the bottom sheet component which I have rendered inside the app. Then there is the top navigation component in which I have added the onClick on the current location that when the state is set in the bottomsheet store, its state changes on the mapping of the components and the focused bottom sheet opens whether its for location, housing or jobs. This Top navigation is being rendered inside various components in the tab navigator screens, and the navigation router controls the switching between the screens. So as you can see in the navigation router the screens mentioned in the stacks in the isEstablished state, when I comment out these screens with rest of the logic being the same, the bottomsheet opens inside the iOS. Otherwise it doesn’t.

"react": "18.2.0",
"react-native": "0.72.6",
"react-native-gesture-handler": "~2.12.0",
"@react-navigation/native-stack": "^6.9.17",
"@react-navigation/stack": "^6.3.20",
"expo": "~49.0.15",
"react-native-reanimated": "^3.3.0",
"@gorhom/bottom-sheet": "^4.6.0",
import React, { useCallback, useMemo, useRef } from "react";
import BottomSheet, { BottomSheetView} from "@gorhom/bottom-sheet";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { SafeAreaView, StyleSheet, Text, View } from "react-native";
import LocationBottomSheetContent from "../Location/LocationBottomSheetContent";
import HousingFilterBottomSheet from "../Filters/HousingFilterBottomSheet";
import useBottomSheetStore from "../../../Stores/BottomSheetStore";
import JobsFiltersBottomSheet from "../Filters/JobsFiltersBottomSheet";
import { useReducedMotion } from "react-native-reanimated";

const mapping = 
    {
        "Location": LocationBottomSheetContent,
        "HousingFilters": HousingFilterBottomSheet,
        "JobsFilters": JobsFiltersBottomSheet,
        // undefined,
    };

const BottomSheetComponent = () => {
    const bottomSheetRef = useRef<BottomSheet>(null);
    const snapPoints = useMemo(() => ["100%"], []);
    const handleSheetChanges = useCallback((index: number) => {
        console.log("handleSheetChanges", index);`your text`
    }, []);
    const { visibleBottomSheet } = useBottomSheetStore();
    const Comp = visibleBottomSheet ? mapping[visibleBottomSheet] : null;
    if (!visibleBottomSheet) return <React.Fragment key={123}></React.Fragment> ;
    // console.log(visibleBottomSheet,Comp);
    
    return(
        <GestureHandlerRootView key={456} style= {styles.bottomsheet} >
            <View style={styles.container}>
                <BottomSheet
                    ref={bottomSheetRef}
                    index={ 0 }
                    snapPoints={snapPoints}
                    onChange={handleSheetChanges}
                    backgroundStyle={styles.backgroundStyle}
                    enablePanDownToClose={true}
                // containerHeight={100}
                // enableDynamicSizing={true}
                >
                    <BottomSheetView style={styles.contentContainer}>
                        <LocationBottomSheetContent />
                    </BottomSheetView>
                </BottomSheet>
            </View>
        </GestureHandlerRootView>
        // <View style={{flex:1,zIndex: 999,}}>
        //     <Text> {visibleBottomSheet? "true" : "False"}</Text>
        // </View>
    );
};

const styles = StyleSheet.create({
    bottomsheet: {
        flex: 1,
        zIndex: 999,
        // backgroundColor: "gray"
        height: "100%",
        // display: "flex",
    },
    contentContainer: {
        // flex: 1,
        // alignItems: "center",
    }, 
    container:{
        flex: 1,
        padding: 24,
    },
    backgroundStyle: {
        borderTopLeftRadius: 40,
        borderTopRightRadius: 40, 
        // backgroundColor: "gray",
    },
    // bottomSheetContainer: {r
    //     // height: 300
    // }
});

export default BottomSheetComponent;
import { StatusBar } from "expo-status-bar";
import React from "react";
import Splash from "./src/components/Screens/OnboardingScreens/Splash";
import NavigationRouter from "./src/components/routes/NavigationRouter";
import BottomSheetComponent from "./src/components/Screens/BottomSheets/BottomSheet/BottomSheetComponent";

const App = () => {
    return (
        <Splash>
            <StatusBar style="auto" />
            <NavigationRouter />   
            <BottomSheetComponent />                    
        </Splash>
    );
};

export default App;
import React from "react";
import { View,Text, StyleSheet,TouchableOpacity, SafeAreaView } from "react-native";
import HamburgerMenu from "../svgs/HamburgerMenu";
import LocationSvg from "../svgs/LocationSvg";
import { useNavigation } from "@react-navigation/native";
import BlueLocationIcon from "../svgs/BlueLocationIcon";
import useBottomSheetStore from "./Stores/BottomSheetStore";

const TopNavigation: React.FC = ()=> {
    const navigation = useNavigation();
    const locationClick = () => {
        navigation.navigate("MapsScreen");
    };
    const { setVisibleBottomSheet } = useBottomSheetStore();

    const toggleBottomSheet = () => {
        setVisibleBottomSheet("Location");
        console.log("location bts toggled");
    };
  
    return(
        <SafeAreaView style={styles.container}>
            <View style={styles.Icon}>
                <HamburgerMenu />
            </View>
            <TouchableOpacity style={styles.topNavText} onPress={toggleBottomSheet}>
                <Text style={[styles.heading]}>Current Location</Text>
                <View style={styles.location}>
                    <BlueLocationIcon/>
                    <Text style={[styles.subHeading, styles.mainText, styles.locationText]}>Iceland</Text> 
                </View>
            </TouchableOpacity>
            <TouchableOpacity
                style= {[styles.Icon]}
                onPress = {locationClick}                
            >
                <LocationSvg />
            </TouchableOpacity>            
        </SafeAreaView>
    );
};

const styles = StyleSheet.create({
    container: {
        flexDirection: "row",
        justifyContent: "space-between",
        padding:10,
    },
    Icon: {
        borderColor: "#EDEDED",
        borderStyle: "solid",
        borderRadius: 10,
        borderWidth: 1,
        padding: 8,
    },
    heading: {
        fontFamily: "Poppins_Paragraph",
        fontSize: 12,
    },
    subHeading: {
        fontFamily: "Poppins_Heading",
        fontSize: 14,
    },
    mainText: {
        textAlign: "center"
    },
    location: {
        flexDirection: "row",
        alignItems: "center"
    },
    locationText: {
        marginLeft: 7,
    },
    topNavText: {
        justifyContent: "center",
        alignContent: "center",
    },

});

export default TopNavigation;
import {create} from "zustand";

type BottomSheetType = "Location" | "HousingFilters" | "JobsFilters" |undefined;

type BottomSheetState = {
    visibleBottomSheet : BottomSheetType;
    setVisibleBottomSheet: (visibleBottomSheet: BottomSheetType) => void; 
}

const useBottomSheetStore = create<BottomSheetState>((set) => ({
    visibleBottomSheet : undefined, 
    setVisibleBottomSheet: (visibleBottomSheet) => {
        // console.log("Before update:", visibleBottomSheet);
        set((state) => ({
            ...state,
            visibleBottomSheet: visibleBottomSheet
        }));
        // console.log("After update:", visibleBottomSheet);
    }
}));


export default useBottomSheetStore;
import HousingScreen from "./Screens/HousingScreen/HousingScreen";
import React, { useEffect } from "react";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import {  Dimensions, StyleSheet, View } from "react-native";
import { RouteProp } from "@react-navigation/native";
import { StackNavigationProp } from "@react-navigation/stack";
import { RootStackParamList } from "./routes/NavigationRouter";
import JobsScreen from "./Screens/JobsScreen/JobsScreen";
import SearchScreen from "./Screens/SearchScreen/SearchScreen";
import SearchSvg from "../svgs/SearchSvg";
import JobSvg from "../svgs/JobSvg";
import HousingSvg from "../svgs/HousingSvg";
import HeartSvg from "../svgs/HeartSvg";
import ProfileSvg from "../svgs/ProfileSvg";
import FocusedSearchSvg from "../svgs/FocusedSearchSvg";
import FocusedJobsSvg from "../svgs/FocusedJobsSvg";
import FocusedHousingSvg from "../svgs/FocusedHousingSvg";
import FocusedHeartSvg from "../svgs/FocusedHeartSvg";
import BottomSheetComponent from "./Screens/BottomSheets/BottomSheet/BottomSheetComponent";
import useStore from "./Stores/store";
// import useStore from "../Stores/store";

type TabNavigatorScreenRouteProp = RouteProp<RootStackParamList, keyof RootStackParamList>;

type TabNavigatorScreenNavigationProp = StackNavigationProp<RootStackParamList>;

type TabNavigatorProps = {
  route?: TabNavigatorScreenRouteProp;
  navigation: TabNavigatorScreenNavigationProp;
};

const Tab = createBottomTabNavigator();

const TabNavigator: React.FC<TabNavigatorProps> = () => {
    const isEstablishedUser = useStore((state) => state.isEstablishedUser);
    const showTabNavigator = useStore((state) => state.showTabNavigator);

    // const hideTabNavigator = useStore((state) => state. hideTabNavigator);

    useEffect(() => {
        if (!isEstablishedUser) {
            showTabNavigator();          
            console.log("user extablished");
        }
    }, []);
    return (
        <View style={styles.viewStyle}>
            <Tab.Navigator
                screenOptions={{
                    tabBarStyle: {
                        backgroundColor: "black",
                        borderRadius: 30,
                        width: 340,
                        height: 56,
                        position:"absolute",
                        marginBottom: 10,                         
                        left: (Dimensions.get("window").width / 2) - 170,                                                                   
                    },
                    tabBarShowLabel: false,
                    tabBarActiveTintColor: "white",
                    tabBarInactiveTintColor: "gray",
                    headerShown: false,
                }}
            >
                <Tab.Screen
                    name="SearchScreen"
                    component={SearchScreen}
                    options={{
                        tabBarIcon: ({ focused }) => (   
                            <View>
                                {focused && <FocusedSearchSvg/>}
                                {!focused && <SearchSvg />}
                            </View>                     
                        ),
                    }}
                />
                <Tab.Screen
                    name="Jobs"
                    component={JobsScreen}
                    options={{
                        tabBarIcon: ({ focused }) => (
                            <View>
                                {focused && <FocusedJobsSvg/>}
                                {!focused && <JobSvg />}
                            </View>
                        ),
                    }}
                />
                <Tab.Screen
                    name="Home"
                    component={HousingScreen}
                    options={{
                        tabBarIcon: ({focused}) => (
                            <View>
                                {focused && <FocusedHousingSvg/>}
                                {!focused && <HousingSvg />}
                            </View>                                                                                                                                                                                                                            
                        ),
                    }}
                />
                <Tab.Screen
                    name="Favorites"
                    component={HousingScreen}
                    options={{
                        tabBarIcon: ({focused}) => (
                            <View>
                                {focused && <FocusedHeartSvg/>}
                                {!focused &&  <HeartSvg />}
                            </View>                           
                        ),
                    }}
                />
                <Tab.Screen
                    name="Person"
                    component={HousingScreen}
                    options={{
                        tabBarIcon: () => (
                            <ProfileSvg />
                        ),
                    }}
                />
            </Tab.Navigator>
            {/* <BottomSheetComponent /> */}
        </View>
    );
};


const styles = StyleSheet.create({
    viewStyle: {
        flex: 1,
        width: "100%",          
    }
});

export default TabNavigator;
import React from "react";
import TabNavigator from "../TabNavigator";
import OnboardingOne from "../Screens/OnboardingScreens/OnboardingOne";
import OnboardingTwo from "../Screens/OnboardingScreens/OnboardingTwo";
import OnboardingThree from "../Screens/OnboardingScreens/OnboardingThree";
import OnboardingFour from "../Screens/OnboardingScreens/OnboardingFour";
import Register from "../Screens/OnboardingScreens/Register";
import Selection from "../Screens/WelcomeScreen";
import TopNavigation from "../TopNavigation";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import useStore from "../Stores/store";
import MapsScreen from "../Screens/MapsScreens/MapsScreen";
import BottomSheetComponent from "../Screens/BottomSheets/BottomSheet/BottomSheetComponent";

export type RootStackParamList = {
    SearchScreen: undefined;
    JobsScreen: undefined;
    HousingScreen: undefined;
    Favorites: undefined;
    Person: undefined;
    Selection: undefined;
    TabNavigator: undefined;
    TopNavigation: undefined;
    MapsScreen: undefined;    
  };
  
const NavigationRouter: React.FC = () =>{
    const Stack = createNativeStackNavigator();
    const isEstablishedUser = useStore((state) => state.isEstablishedUser);
    return (
        <NavigationContainer>
            <Stack.Navigator screenOptions={{ headerShown: false, animation: "slide_from_right" }}>
                {!isEstablishedUser && (
                    <>
                        <Stack.Screen name="OnboardingOne" component={OnboardingOne} />
                        <Stack.Screen name="OnboardingTwo" component={OnboardingTwo} />
                        <Stack.Screen name="OnboardingThree" component={OnboardingThree} />
                        <Stack.Screen name="OnboardingFour" component={OnboardingFour} />
                        <Stack.Screen name="Register" component={Register} />
                    </>
                )}
                <Stack.Screen
                    name="TabNavigator"
                    component={TabNavigator as React.ComponentType }
                    options={{ presentation: "transparentModal" }}
                />
                <Stack.Screen name="Selection" component={Selection} />
                <Stack.Screen name="TopNavigation" component={TopNavigation} />
                <Stack.Screen name="MapsScreen" component={MapsScreen} />
                {/* <Stack.Screen name="BottomSheet" component={BottomSheetComponent} /> */}

                {/* <BottomSheetComponent /> */}

            </Stack.Navigator>
            
        </NavigationContainer>    
    );
};

export default NavigationRouter;

So far I have tried doing a lot of things. In the start I had been focusing on the just the involved components and the store i.e, <BottomSheetComponent/>, <App>, <BottomSheetStore/> & <TopNavigation/>. I tried removing the if/else logic from the <BottomSheetComponent/> but then I figured out that the problem was how the navigation router was implemented and how the tab navigator was implemented. Because when inside the tab navigator screen, the bottomsheet doesn’t work when I directly render it inside the app it starts working but obviously I don’t want that. I also tried searching for the same issue on Github but people had written that there might be an issue with my react-native-reanimated version but I don’t think thats the issue here.

2

Answers


  1. Chosen as BEST ANSWER

    So after so many days of researching and literally frisking my code base i found out that the issue was in my navigation router where i had mentioned tab navigator in the stack.

    <Stack.Screen name="TabNavigator" component={TabNavigator as React.ComponentType } options={{ presentation: "transparentModal" }}

    />
    

    here in the options the presentation was set to tranparent modal and because of that i was not able to make it work properly as it was displaying in the background. i checked this by making my opacity = 0.5 in the ios so i could see if there was something in the back. and the tab navigator was opening in the back because of this "tranparentModal" option


  2. To be on a safer side, customize your own. I’m facing similar issues now. I’ll build something from scratch I can control in the future, which I’ll share with you probably

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search