Implementing Bottom Sheets Like a Pro in React Native

Shubham JainShubham Jain
3 min read

When building a React Native app, one of the most common UI patterns you'll encounter is the bottom sheet—a UI element that slides up from the bottom of the screen, often used for menus, options, or additional details. While many developers might implement this as a standalone component within their screens, there's a more efficient and scalable way: making the bottom sheet a separate screen.

Why Make It a Separate Screen?

The traditional approach of embedding a bottom sheet as a component within various screens can lead to several challenges:

  1. UI Management: Handling the bottom sheet's UI across different screens can become cumbersome, especially when dealing with varying screen sizes and content.

  2. State Handling: Managing the state and data for the bottom sheet within the parent component often leads to tightly coupled code, making it harder to maintain and test.

  3. Reusability: A component-based bottom sheet is often tied to a specific screen, reducing its reusability across the app.

By creating the bottom sheet as a separate screen, you gain the following advantages:

  • Isolation: The bottom sheet screen is isolated from the rest of the app, meaning it can handle its own state, UI, and data fetching without interference from the parent component.

  • Reusability: This approach allows you to trigger the bottom sheet from anywhere in the app, simply by navigating to the bottom sheet screen with the appropriate parameters.

  • Scalability: As your app grows, this pattern allows you to easily manage complex UI scenarios without cluttering your main components.


Implementing the Bottom Sheet as a Separate Screen

Let’s dive into how you can implement this approach in your React Native app.

// MenuScreen.js

import React, { useEffect, useState } from 'react';
import { View, Text, FlatList, TouchableOpacity } from 'react-native';
import { useNavigation, useRoute } from '@react-navigation/native';

const MenuScreen = () => {
  const [menuOptions, setMenuOptions] = useState([]);
  const navigation = useNavigation();
  const route = useRoute();

  useEffect(() => {
    const { source } = route.params;
    // Fetch the menu options based on the source parameter
    fetchMenuOptions(source);
  }, [route.params]);

  const fetchMenuOptions = async (source) => {
    try {
      // Make an API call with the source parameter
      const response = await fetch(`https://api.example.com/menu?source=${source}`);
      const data = await response.json();
      setMenuOptions(data.options);
    } catch (error) {
      console.error('Failed to fetch menu options', error);
    }
  };

  const handleMenuOptionPress = (item) => {
    console.log(`Selected option: ${item.name}`);
  };

  return (
    <View style={{ flex: 1, backgroundColor: 'white', padding: 20 }}>
      <FlatList
        data={menuOptions}
        renderItem={({ item }) => (
          <TouchableOpacity onPress={() => handleMenuOptionPress(item)}>
            <Text style={{ padding: 10 }}>{item.name}</Text>
          </TouchableOpacity>
        )}
        keyExtractor={(item) => item.id}
      />
    </View>
  );
};

export default MenuScreen;

Navigating to the Bottom Sheet

Now, instead of embedding a bottom sheet component, you navigate to this screen and pass the relevant parameters:

// In your main screen component

import { useNavigation } from '@react-navigation/native';

const MainScreen = () => {
  const navigation = useNavigation();

  const openMenu = (menuType) => {
    navigation.navigate('MenuScreen', { source: menuType });
  };

  return (
    <View style={{ flex: 1 }}>
      {/* Other UI elements */}
      <TouchableOpacity onPress={() => openMenu('chatmenu')}>
        <Text>Open Chat Menu</Text>
      </TouchableOpacity>

      <TouchableOpacity onPress={() => openMenu('detailmenu')}>
        <Text>Open Detail Menu</Text>
      </TouchableOpacity>
    </View>
  );
};

export default MainScreen;

Conclusion

By implementing the bottom sheet as a separate screen, you can avoid the pitfalls of traditional component-based approaches, achieving a cleaner, more scalable codebase. This method allows for greater flexibility and ease of use across your entire application, ensuring that your bottom sheet behaves consistently, regardless of where it's used.


In the next article, we'll delve into how to manage this menu and its actions properly on an industry level, ensuring that your app remains robust and maintainable as it grows. Happy coding!

10
Subscribe to my newsletter

Read articles from Shubham Jain directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Shubham Jain
Shubham Jain

I work as an SDE-1 in frontend role at a healthcare startup. I am always curious to learn new technologies and share my learnings. I love development and love to code.