Why my Bottom Tabs Navigator is re rendering unnecessary?

Viewed 451

I am making an app in which there are three bottom tabs screen. HomeScreen, CartScreen and Profile Screen. I was wanting to check the re renders of my app using "Why did you re render" npm package and found a critical bug or is it so.

The MainTabScreen(The screen in which all the bottom tabs are nested) is re rendering as many times I change the screen, just because its props changed. Here is the console log : Console log

Here is the code of the MainTabScreen.js:


const MainTabScreen = () => {
  return (
    <Tab.Navigator
      tabBarOptions={{
         showLabel: false,
         style: {
           position: "absolute",
           height: 40,
           bottom: 0,
           right: 0,
           left: 0,
           backgroundColor: "#fff",
         },
      }}
    >
      <Tab.Screen
        name="MainHome"
        component={MainHomeScreen}
        options={{
          tabBarIcon: ({ focused }) => (
            <Icon.Home
              // color={"#f62459"}
              color={focused ? "#f62459" : "#302f2f"}
              height={28}
              width={28}
            />
          ),
        }}
      />
      <Tab.Screen
        name="MainCart"
        component={MainCartScreen}
        options={{
          tabBarIcon: ({ focused }) => (
            <Icon.ShoppingCart
              // color="#302f2f"
              color={focused ? "#f62459" : "#302f2f"}
              width={28}
              height={28}
            />
          ),
        }}
      />
      <Tab.Screen
        name="MainProfile"
        component={MainProfileScreen}
        options={{
          tabBarIcon: ({ focused }) => (
            <Icon.User
              // color="#302f2f"
              color={focused ? "#f62459" : "#302f2f"}
              height={28}
              width={28}
            />
          ),
        }}
      />
    </Tab.Navigator>
  );
};

export default MainTabScreen;


Edit 11:27 05-09-21

The MainTabScreen renders inside AppStack screen which renders inside the AuthStack.js for authentication and this AuthStack.js renders inside the App.js

Here is the AppStack.js code:


const AppStack = () => {
   return(
    <Stack.Navigator screenOptions={{ headerShown: false }}>
      <Stack.Screen name="MainTabScreen" component={MainTabScreen} />
      <Stack.Screen name="Product" component={Product} />
      <Stack.Screen name="OrderScreen" component={OrderScreen} />
    </Stack.Navigator>
   ) 

This is the AuthStack.js

import React, {
  useState,
  useEffect,
  useMemo,
  useReducer,
  useContext,
} from "react";
import { View, Text, Platform } from "react-native";
import AppStack from "./navigation/AppStack";
import RootStack from "./navigation/RootStack";
import { AuthContext } from "./context";
import * as SecureStore from "expo-secure-store";
import LottieView from "lottie-react-native";
import { useIsMounted } from "../screens/useIsMounted";

const AuthStack = () => {
  const initialLoginState = {
    isLoading: true,
    accessToken: null,
  };

  // The rest of the authentication logic...

  return (
    <AuthContext.Provider value={authContext}>
      {loginState.accessToken !== null ? <AppStack /> : <RootStack />}
    </AuthContext.Provider>
  );
};

export default AuthStack;

App.js

 import React from "react";
import { StyleSheet, Text, View, Dimensions } from "react-native";
import { NavigationContainer } from "@react-navigation/native";
import store from "./redux/store";

const App = () => {
  return (
    <Provider store={store}>
      <NavigationContainer>
        <AuthStack />
      </NavigationContainer>
    </Provider>
  );
};

export default App;

1 Answers

i found the solution... use:

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
const Tab = createBottomTabNavigator();

`<Tab.Navigator
      tabBar={props => <MyTabBar {...props} />}>`

create separately TabBar (for example):

    function MyTabBar({ state, descriptors, navigation, position }) {
  const edge = useSafeAreaInsets();
  const { colors } = useTheme();
  return (
    <View style={{ flexDirection: 'row', height: edge.bottom + 70, alignItems: 'center', justifyContent: 'space-between', backgroundColor: colors.cell }}>
      {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 onPress = () => {
          const event = navigation.emit({
            type: 'tabPress',
            target: route.key,
            canPreventDefault: true,
          });

          if (!isFocused && !event.defaultPrevented) {
            // The `merge: true` option makes sure that the params inside the tab screen are preserved
            navigation.navigate({ name: route.name, merge: true });
          }
        };



        if (label === 'Browse Radios') {
          return <CenterTabBar isFocused={isFocused} onPress={() => { onPress(); }} />
        } else {
          return <MyTabBarButton isFocused={isFocused} onPress={() => { onPress(); }} label={label} />
        }
      })}
    </View>
  );
}

and create separately buttons for TabBar (for example):

    const CenterTabBar = ({ onPress, isFocused }) => {
  return (
    <TouchableOpacity style={{
      alignItems: 'center',
      flex: 1
    }}
      onPress={() => {
        onPress();
      }}
    >
      {!isFocused && <Image style={styles.centerTabBar} source={require('../../assets/images/tab_browse.png')} />}
      {isFocused && <Image style={styles.centerTabBar} source={require('../../assets/images/tab_browse_.png')} />}
    </TouchableOpacity>
  );
}

const MyTabBarButton = ({ onPress, isFocused, label }) => {
  const { colors, dark } = useTheme();
  return (
    <TouchableOpacity style={{
      alignItems: 'center',
      flex: 1
    }}
      onPress={() => { onPress() }}
    >
      <Animated.Image style={[styles.icon_tab, { tintColor: isFocused ? '#00ACEC' : colors.tint }]} source={GetIconTab(label)} />
      {isFocused && <Animated.View style={styles.circle} entering={BounceIn} />}
    </TouchableOpacity>
  );
}
Related