Sana
Sana

Reputation: 347

useEffect doesn't work when switching screens

Hi I am still new to react-native and has been trying to create an app. My stuck is that I don't know why useEffect doesn't work when switching screens by react-navigation-bottom-tab. Below is my HomeScreen.js where I wrot useEffect to fetch all data from Firestore. As you can see I wrote two useEffects because I thought it'd work. The first one was thought to fetch data when I switch to Home from like ProfileScreen.

import {
  View,
  FlatList,
  StyleSheet,
} from "react-native";
import { RideCard } from "./RideCard";
import { OneTouchFilter } from "./OneTouchFilter";
import { useFirestoreContext } from "../../contexts/FirestoreContext";
import { useEffect } from "react";

export const HomeScreen = ({ navigation }) => {
  console.log("HomeScreen.js useEffect");
  const { selectedBoardType, cityFromText, cityToText, fetchRides, rides } =
    useFirestoreContext();

  useEffect(() => {
    fetchRides();
  }, []);
  
  useEffect(() => {
    fetchRides();
  }, [selectedBoardType, cityFromText, cityToText]);

  return (
    <View style={styles.inner}>
      <OneTouchFilter />
      <FlatList
        data={rides}
        renderItem={(itemData) => (
          <RideCard
            ride={itemData.item}
            index={itemData.index}
            id={itemData.item.id}
            numOfRides={rides.length}
          />
        )}
      />
    </View>
  );
};

App.js

this is a file where react-navigation-bottom-tab placed in.

import React, { useContext } from "react";
import { StyleSheet } from "react-native";
import { NavigationContainer, DefaultTheme } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { HomeScreen } from "./screens/Home/HomeScreen";
import { PostScreen } from "./screens/Post/PostScreen";
import { ProfileScreen } from "./screens/Profile/ProfileScreen";
import Ionicons from "react-native-vector-icons/Ionicons";
import { NativeBaseProvider } from "native-base";
// create another file for contexts Provider
import { AuthContextProvider } from "./contexts/AuthContext";
import { FirestoreContextProvider } from "./contexts/FirestoreContext";
import { FormContextProvider } from "./contexts/FormContext";
const MyTheme = {
  ...DefaultTheme,
  colors: {
    ...DefaultTheme.colors,
    background: "white",
  },
};

export default function App() {
  const Stack = createStackNavigator();
  // タブ移動の設定を新規追加
  // createBottomTabNavigator ... タブ移動を設定する関数
  const Tab = createBottomTabNavigator();

  // 新規追加
  // - 移動を関数に持たせて、タブ移動の設定で利用
  // - 意図 ... タブ移動の箇所のコードが読みにくくなるため
  const Home = () => {
    return (
      <Stack.Navigator>
        <Stack.Screen
          options={{ headerShown: false }}
          name="Home"
          component={HomeScreen}
        />
      </Stack.Navigator>
    );
  };

  const Post = () => {
    return (
      <Stack.Navigator
        headerMode="screen"
        screenOptions={{ headerShown: false }}
      >
        <Stack.Screen name="Post" component={PostScreen} />
        {/* <Stack.Screen name="詳細" component={DetailsScreen} /> */}
      </Stack.Navigator>
    );
  };

  const Profile = () => {
    return (
      <Stack.Navigator
        headerMode="screen"
        screenOptions={{ headerShown: false }}
      >
        <Stack.Screen name="Profile" component={ProfileScreen} />
        {/* <Stack.Screen name="詳細" component={DetailsScreen} /> */}
      </Stack.Navigator>
    );
  };

  return (
    <AuthContextProvider>
      <FirestoreContextProvider>
        <FormContextProvider>
          <NativeBaseProvider>
            <NavigationContainer theme={MyTheme}>
              <Tab.Navigator
                screenOptions={({ route }) => ({
                  tabBarIcon: ({ focused, color, size }) => {
                    let iconName;
                    // icon swithcer which depends on the route name
                    if (route.name === "Home") {
                      iconName = focused ? "ios-home" : "ios-home";
                    } else if (route.name === "Post") {
                      iconName = focused ? "ios-add" : "ios-add";
                    } else if (route.name === "Profile") {
                      iconName = focused ? "md-person" : "md-person";
                    }
                    return (
                      <Ionicons name={iconName} size={size} color={color} />
                    );
                  },
                })}
                tabBarOptions={{
                  activeTintColor: "rgb(0, 110, 182)",
                  inactiveTintColor: "gray",
                }}
              >
                <Tab.Screen name="Home" component={Home} />
                <Tab.Screen name="Post" component={Post} />
                <Tab.Screen name="Profile" component={Profile} />
              </Tab.Navigator>
            </NavigationContainer>
          </NativeBaseProvider>
        </FormContextProvider>
      </FirestoreContextProvider>
    </AuthContextProvider>
  );
}

Upvotes: 2

Views: 1656

Answers (1)

adsy
adsy

Reputation: 11392

It's because, even though you switch screens, the other screen is not unmounted --- it's still in memory but not visible. This is a design decision of react-navigation intended for better performance (it doesn't have to reload the screen when you go back, as it's already there). Since it is not unmounted, when the user returns to it, it just triggers a rerender of the already-instantiated component, so the effect does not run.

What you need to use instead is useFocusEffect which is an effect bound to if the screen is in focus.

Upvotes: 4

Related Questions