bsantoss
bsantoss

Reputation: 437

How to render a Modal within a Tab Screen in React Navigation

I need to render a modal when the user press in the middle button. I'm using react-native-raw-bottom-sheet library to provide a Modal to my application. I tried to pass a prop isFocused={props.navigation.isFocused} inside the <Tab.Screen> but the problem is when I pass the props to based if is or not focused in the the is rendered two times instead one.

I also tried to trigger the modal direct by the but without success.

My problematic is, when the user press the i need render the new that will contain the hole logic of the content in the modal and also will render the modal.

Bottom Tab Navigation

My tab.routes.js

import React from 'react';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import TabButton from '../components/Tab/Button';
import Icon from 'react-native-vector-icons/MaterialIcons';

import Home from '../containers/Home';
import Adjustment from '../containers/Adjustment';
import Graphic from '../containers/Graphic';
import Help from '../containers/Help';
import NewTransaction from '../containers/NewTransaction';

const icons = {
  Home: {
    name: 'home',
  },
  Graphic: {
    name: 'pie-chart',
  },
  NewTransaction: {
    name: 'notifications-none',
  },
  Help: {
    name: 'help-outline',
  },
  Adjustment: {
    name: 'settings',
  },
};

const Tab = createBottomTabNavigator();

const TabRoutes = () => (
  <Tab.Navigator
    initialRouteName="HomeScreen"
    screenOptions={({route, navigation}) => ({
      tabBarIcon: ({color, size, focused}) => {
        if (route.name === 'NewTransaction') {
          return <TabButton focused={focused} onPress={() => navigation.navigate('NewTransaction')} />;
        }
        const {name} = icons[route.name];
        return <Icon name={name} size={size} color={color} />;
      },
    })}
    tabBarOptions={{
      keyboardHidesTabBar: true,
      activeTintColor: '#f8b006',
      inactiveTintColor: '#1C3041',
      style: {
        height: 60,
      },
      iconStyle: {
        marginTop: 5,
      },
      labelStyle: {
        fontSize: 12,
        marginBottom: 10,
      },
    }}>
    <Tab.Screen
      options={{
        title: 'Home',
      }}
      name="Home"
      component={Home}
    />
    <Tab.Screen
      options={{
        title: 'Gráfico',
      }}
      name="Graphic"
      component={Graphic}
    />
    <Tab.Screen
      options={{
        title: '',
      }}
      name="NewTransaction"
      component={NewTransaction}
    />
    <Tab.Screen
      options={{
        title: 'Ajuda',
      }}
      name="Help"
      component={Help}
    />
    <Tab.Screen
      options={{
        title: 'Ajustes',
      }}
      name="Adjustment">
      {(props) => (
        <Adjustment isVisible={props.navigation.isFocused()} onPress={() => props.navigation.navigate('Home')} />
      )}
    </Tab.Screen>
  </Tab.Navigator>
);

export default TabRoutes;

Tab/Button/index.js

import React from 'react';
import {TouchableWithoutFeedback} from 'react-native-gesture-handler';
import Icon from 'react-native-vector-icons/MaterialIcons';
import Button from './styles';

const TabButton = ({onPress, focused}) => {
  return (
    <TouchableWithoutFeedback onPress={onPress}>
      <Button focused={focused}>
        <Icon name="add" size={35} color={'white'} />
      </Button>
    </TouchableWithoutFeedback>
  );
};

export default TabButton;

And the component that will display the modal content

import React from 'react';
import {Text, View} from 'react-native';
const NewTransaction = ({isVisible}) => {
  return (
    <View>
      <Text>Welcome to NewTransactions </Text>
    </View>
  );
};

export default NewTransaction;

Upvotes: 5

Views: 5597

Answers (1)

Anhdevit
Anhdevit

Reputation: 2104

This is my home tab it looks like to you

enter image description here

I custom tab bar with code but the add button is not a screen it is just a button and popup options to select

enter image description here

import {hideModalCreate, showModalCreate} from '@features/loading/actions';
import CreateYCTV from '@features/main/CreateYCTV';
import HomeScreen from '@features/main/Home';
import Manager from '@features/main/Manager';
import Notification from '@features/main/Notification';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import images from '@res/icons';
import * as React from 'react';
import {Image, Pressable, View} from 'react-native';
import {Text, useTheme} from 'react-native-paper';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {connect} from 'react-redux';
import ProductStack from './ProductStack';

const Tab = createBottomTabNavigator();

function MyTabBar({
  state,
  descriptors,
  navigation,
  showModalCreate,
  hideModalCreate,
  isShowModalCreate,
}) {
  const {colors} = useTheme();
  const insets = useSafeAreaInsets();

  const focusedOptions = descriptors[state.routes[state.index].key].options;

  if (focusedOptions.tabBarVisible === false) {
    return null;
  }

  return (
    <View
      style={{
        flexDirection: 'row',
        backgroundColor: '#FFFFFF',
        paddingBottom: Math.max(insets.bottom, 0),
      }}>
      {state.routes.map((route, index) => {
        const {options} = descriptors[route.key];
        const label =
          options.tabBarLabel !== undefined
            ? options.tabBarLabel
            : options.title !== undefined
            ? options.title
            : route.name;

        const isFocused = state.index === index;

        const getSourceImage = (isFocused) => {
          switch (route.name) {
            case 'home':
              return isFocused ? images.tab_home1 : images.tab_home;
            case 'loans':
              return isFocused ? images.tab_searching1 : images.tab_searching;
            case 'notification':
              return isFocused ? images.notifications1 : images.notifications;
            case 'manager':
              return isFocused
                ? images.tab_paper_folder1
                : images.tab_paper_folder;
            default:
              return images.tab_add;
          }
        };

        const onPress = () => {
          if (route.name === 'create') {
            if (isShowModalCreate) {
              hideModalCreate();
              return;
            }
            showModalCreate();
            return;
          }
          hideModalCreate();
          const event = navigation.emit({
            type: 'tabPress',
            target: route.key,
            canPreventDefault: true,
          });

          if (!isFocused && !event.defaultPrevented) {
            navigation.navigate(route.name);
          }
        };

        const onLongPress = () => {
          navigation.emit({
            type: 'tabLongPress',
            target: route.key,
          });
        };

        return (
          <Pressable
            accessibilityRole="button"
            accessibilityStates={isFocused ? ['selected'] : []}
            accessibilityLabel={options.tabBarAccessibilityLabel}
            testID={options.tabBarTestID}
            onPress={onPress}
            onLongPress={onLongPress}
            style={{
              flex: 1,
              alignItems: 'center',
              justifyContent: 'center',
              paddingVertical: 8,
              backgroundColor: 'white',
            }}>
            <Image source={getSourceImage(isFocused)} />
            {route.name != 'create' ? (
              <Text
                style={{
                  color: isFocused ? colors.primary : colors.placeholder,
                  fontSize: 10,
                  marginTop: 4,
                }}>
                {label}
              </Text>
            ) : null}
          </Pressable>
        );
      })}
    </View>
  );
}

const Tabbar = ({showModalCreate, hideModalCreate, isShowModalCreate}) => {
  return (
    <Tab.Navigator
      tabBar={(props) => (
        <MyTabBar
          isShowModalCreate={isShowModalCreate}
          showModalCreate={showModalCreate}
          {...props}
          hideModalCreate={hideModalCreate}
        />
      )}>
      <Tab.Screen
        name="home"
        component={HomeScreen}
        options={{
          title: 'Trang chủ',
        }}
      />
      <Tab.Screen
        name="loans"
        component={ProductStack}
        options={{
          title: 'Sản phẩm',
        }}
      />
      <Tab.Screen name="create" component={CreateYCTV} />
      <Tab.Screen
        name="notification"
        component={Notification}
        options={{
          title: 'Thông báo',
          tabBarBadge: '13',
        }}
      />
      <Tab.Screen
        name="manager"
        component={Manager}
        options={{
          title: 'Quản lý',
        }}
      />
    </Tab.Navigator>
  );
};

const mapStateToProps = (state, ownProps) => {
  return {
    isShowModalCreate: state.loading.isShowModalCreate,
  };
};

const mapDispatch = {
  showModalCreate: showModalCreate,
  hideModalCreate: hideModalCreate,
};

export default connect(mapStateToProps, mapDispatch)(Tabbar);

Upvotes: 5

Related Questions