Home > OS >  useEffect doesn't work when switching screens
useEffect doesn't work when switching screens

Time:12-06

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>
  );
}

CodePudding user response:

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.

CodePudding user response:

It is possible that the useEffect hook in your HomeScreen component is not being triggered when you switch to the Home screen because the component is not being unmounted and re-mounted. In React Native, when you navigate to a new screen using the react-navigation-bottom-tab, the previous screen is not unmounted and remains in memory. This means that the useEffect hook will not be triggered again unless the component is unmounted and re-mounted.

To fix this issue, you can try changing the dependencies array of your useEffect hook to include the selectedBoardType, cityFromText, and cityToText variables. This will cause the useEffect hook to be triggered whenever these variables change, which should happen when you switch to the Home screen.

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

Alternatively, you can use the React Navigation hook useFocusEffect() instead of useEffect(). This hook is specifically designed for triggering effects when a screen becomes focused, which should happen when you switch to the Home screen.

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

export const HomeScreen = ({ navigation }) => {
  const { selectedBoardType, cityFromText, cityToText, fetchRides, rides } =
    useFirestoreContext();

  useFocusEffect(
    React.useCallback(() => {
      fetchRides();
    }, [selectedBoardType, cityFromText, cityToText])
  );

  return (
    // ...
  );
};
  • Related