react-nativereact-navigationreact-navigation-stackreact-navigation-bottom-tab

Stacked React Navigators cause API to be called 2x when component is instantiated


I'm new to React Native and I have an app which uses a stack and tab navigator. The stack navigator is the child navigator of the tab navigator. The problem lies when a screen uses both of them, causing the useEffect in the component to be called twice. How can I fix this?

This is the App.js which contains the navigators:

const App = () => {
  return (
    <NavigationContainer>
      <TabNavigator />
    </NavigationContainer>
  );
};

const StackNavigator = () => {
  return (
    <Stack.Navigator>
      <Stack.Screen
        name="HomeScreen"
        component={HomeScreen}
        options={{ headerShown: false }}
      />
      <Stack.Screen
        name="Discover"
        component={DiscoverScreen}
        options={{ headerShown: false }}
      />
      <Stack.Screen
        name="MyGarden"
        component={MyGardenScreen}
        options={{ headerShown: false }}
      />
      <Stack.Screen
        name="Planty"
        component={PlantyScreen}
        options={{ headerShown: false }}
      />
      <Stack.Screen
        name="Specific"
        component={SpecificPlantScreen}
        options={{ headerShown: false }}
      />
    </Stack.Navigator>
  );
};

const TabNavigator = () => {
  return (
    <Tab.Navigator
      initialRouteName="Home"
      screenOptions={() => ({
        tabBarStyle: {
          height: 80,
          backgroundColor: "#232516",
          paddingBottom: 5,
        },
        headerShown: false,
        tabBarActiveTintColor: "white",
        tabBarInactiveTintColor: "gray",
      })}
    >
      <Tab.Screen
        name="Home"
        component={StackNavigator}
        options={{
          tabBarIcon: ({ focused }) => (
            <FontAwesome
              style={focused ? styles.focusedNavButtonBackground : {}}
              name="home"
              size={35}
              color={focused ? "black" : "white"}
            />
          ),
        }}
      />
      <Tab.Screen
        name="Discover"
        component={DiscoverScreen}
        options={{
          tabBarIcon: ({ focused }) => (
            <FontAwesome
              style={focused ? styles.focusedNavButtonBackground : {}}
              name="search"
              size={35}
              color={focused ? "black" : "white"}
            />
          ),
        }}
      />
      <Tab.Screen
        name="MyGarden"
        component={MyGardenScreen}
        options={{
          tabBarIcon: ({ focused }) => (
            <FontAwesome6
              style={focused ? styles.focusedNavButtonBackground : {}}
              name="sun-plant-wilt"
              size={35}
              color={focused ? "black" : "white"}
            />
          ),
        }}
      />
    </Tab.Navigator>
  );
};

And this is the DiscoverScreen which is in both of the navigators:

const DiscoverScreen = ({ navigation }) => {
  const [getPlants, incrementPageNumber, page, plants, errorMessage] =
    usePlants();

  useEffect(() => {
    console.log("API called");
    getPlants(page);
  }, [page]);

  // ... rest of the component
};

Also, the usePlants logic:

useEffect(() => {
  console.log("API called");
  getPlants(page);
}, [page]);

Any help would be greatly appreciated!

I also tried to update only one of the navigators, but it caused the tab components or the stack to not update.


Solution

  • You have 2 Discover items

          <Stack.Screen
            name="Discover"
            component={DiscoverScreen}
            options={{ headerShown: false }}
          />
    
    ...
    
          <Tab.Screen
            name="Discover"
            component={DiscoverScreen}
            options={{
              tabBarIcon: ({ focused }) => (
                <FontAwesome
                  style={focused ? styles.focusedNavButtonBackground : {}}
                  name="search"
                  size={35}
                  color={focused ? "black" : "white"}
                />
              ),
            }}
          />
    

    Simply renaming one of them should do the trick

    For example

          <Stack.Screen
            name="Discover"
            component={DiscoverScreen}
            options={{ headerShown: false }}
          />
    
    ...
    
          <Tab.Screen
            name="DiscoverTab"
            component={DiscoverScreen}
            options={{
              tabBarIcon: ({ focused }) => (
                <FontAwesome
                  style={focused ? styles.focusedNavButtonBackground : {}}
                  name="search"
                  size={35}
                  color={focused ? "black" : "white"}
                />
              ),
            }}
          />