I'm new to React Native, and I'm facing an issue when trying to fetch the user token to check if the user is authenticated. If the token is found, I consider the user authenticated and attempt to display the root stack. However, the problem I'm encountering is that the screens from the AuthStack are still being mounted on top of the RootStack. Can Someone please help me
below is my code:
import { router, Slot, Stack, Tabs } from "expo-router";
import { StatusBar } from "expo-status-bar";
import { useContext, useEffect, useState } from "react";
import { AuthContext, AuthContextProvider } from "../context/AuthContext";
import { ActivityIndicator, View } from "react-native";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { getUserInforWithToken } from "../controller/AuthController";
function RootStack() {
return (
<Stack>
<Stack.Screen name="(root)/index" options={{ title: "Welcome" }} />
</Stack>
);
}
function AuthStack() {
return (
<Stack
screenOptions={{
headerStyle: { backgroundColor: "#6779ef" },
headerTintColor: "white",
contentStyle: { backgroundColor: "#6779ef" },
headerShown: false,
}}>
<Stack.Screen name="(auth)/index" options={{ title: "Login Page" }} />
<Stack.Screen name="(auth)/signup" options={{ title: "Sign Up Page" }} />
</Stack>
);
}
function Root() {
const { setIsLogin, setToken, setIsTryingLogin, isTryingLogin } =
useContext(AuthContext);
const [isLoading, setIsLoading] = useState(true);
const { isLogin } = useContext(AuthContext);
useEffect(() => {
const checkAuth = async () => {
const token = await AsyncStorage.getItem("token");
if (token) {
console.log("token found, user logged in");
setIsLogin(true);
setToken(token);
} else {
setIsLogin(false);
}
// Set trying login to false after we check for token
setIsTryingLogin(false);
};
checkAuth();
}, []); // This runs only once on component mount
useEffect(() => {
if (!isTryingLogin) {
setIsLoading(false);
}
}, [isTryingLogin]);
if (isLoading) {
console.log("Loading...");
return (
<View className="flex-1 justify-center items-center">
<ActivityIndicator className="p-2 m-2" animating size="large" />
</View>
);
}
return isLogin ? <RootStack /> : <AuthStack />;
}
export default function Layout() {
return (
<AuthContextProvider>
<StatusBar style="light" />
<Root />
</AuthContextProvider>
);
}
I tried Chatgpt and tried reading docs and even tried to follow someone youtube channel noting worked
The issue you're encountering is likely due to both stacks (RootStack and AuthStack) being mounted simultaneously in your current setup.
instead of rendering both stack conditionally In the root stack, conditionally render the correct stack in the stack navigator itself based on the isLogin state.
eg.
import { router, Slot, Stack, Tabs } from "expo-router";
import { StatusBar } from "expo-status-bar";
import { useContext, useEffect, useState } from "react";
import { AuthContext, AuthContextProvider } from "../context/AuthContext";
import { ActivityIndicator, View } from "react-native";
import AsyncStorage from "@react-native-async-storage/async-storage";
function Root() {
const { setIsLogin, setToken, setIsTryingLogin, isTryingLogin, isLogin } =
useContext(AuthContext);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const checkAuth = async () => {
const token = await AsyncStorage.getItem("token");
if (token) {
console.log("token found, user logged in");
setIsLogin(true);
setToken(token);
} else {
setIsLogin(false);
}
// Set trying login to false after we check for token
setIsTryingLogin(false);
};
checkAuth();
}, []); // This runs only once on component mount
useEffect(() => {
if (!isTryingLogin) {
setIsLoading(false);
}
}, [isTryingLogin]);
if (isLoading) {
console.log("Loading...");
return (
<View className="flex-1 justify-center items-center">
<ActivityIndicator className="p-2 m-2" animating size="large" />
</View>
);
}
return (
<Stack
screenOptions={{
headerShown: false, // Hides header for all screens by default
}}
>
{isLogin ? (
<>
{/* Root Stack for authenticated users */}
<Stack.Screen
name="(root)/index"
component={RootStack}
options={{ title: "Welcome" }}
/>
</>
) : (
<>
{/* Auth Stack for unauthenticated users */}
<Stack.Screen
name="(auth)/index"
component={AuthStack}
options={{ title: "Login Page" }}
/>
<Stack.Screen
name="(auth)/signup"
component={AuthStack}
options={{ title: "Sign Up Page" }}
/>
</>
)}
</Stack>
);
}
function RootStack() {
return (
<Stack>
<Stack.Screen name="(root)/index" options={{ title: "Welcome" }} />
</Stack>
);
}
function AuthStack() {
return (
<Stack
screenOptions={{
headerStyle: { backgroundColor: "#6779ef" },
headerTintColor: "white",
contentStyle: { backgroundColor: "#6779ef" },
headerShown: false,
}}
>
<Stack.Screen name="(auth)/index" options={{ title: "Login Page" }} />
<Stack.Screen name="(auth)/signup" options={{ title: "Sign Up Page" }} />
</Stack>
);
}
export default function Layout() {
return (
<AuthContextProvider>
<StatusBar style="light" />
<Root />
</AuthContextProvider>
);
}