[Error: Attempted to navigate before mounting the Root Layout component. Ensure the Root Layout component is rendering a Slot, or other navigator on the first render.][Component Stack]
해석 : 루트 레이아웃 컴포넌트를 마운트하기 전에 탐색을 시도했다. 루트 레이아웃 컴포넌트가 첫 번째 렌더링에서 슬롯 또는 다른 네비게이터를 렌더링하고 있는지 확인해라
전체 코드
import FontAwesome from '@expo/vector-icons/FontAwesome';
import { useFonts } from 'expo-font';
import { Redirect, Stack, useRouter } from 'expo-router';
import * as SplashScreen from 'expo-splash-screen';
import { useEffect } from 'react';
import 'react-native-reanimated';
import { TamaguiProvider } from '@tamagui/core'
import { config } from '../tamagui.config';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { StatusBar } from 'react-native'
import { useAuth } from '../hooks/useAuth';
// root 레이아웃 (App.jsx 대용)
export {
// Catch any errors thrown by the Layout component.
ErrorBoundary,
} from 'expo-router';
export const unstable_settings = {
// Ensure that reloading on `/modal` keeps a back button present.
initialRouteName: '(tabs)',
};
// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
// 폰트 적용
const [loaded, error] = useFonts({
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
...FontAwesome.font,
});
// Expo Router uses Error Boundaries to catch errors in the navigation tree.
useEffect(() => {
if (error) throw error;
}, [error]);
useEffect(() => {
if (loaded) {
SplashScreen.hideAsync();
}
}, [loaded]);
if (!loaded) {
return null; // 폰트가 로딩 중이면 아무것도 렌더링 하지 않음
}
return <RootLayoutNav />;
}
function RootLayoutNav() {
const { user, loading } = useAuth(); // useAuth 훅 사용
const router = useRouter(); // useRouter 훅 사용
if(loading) return null // 로딩 중이면 렌더링 하지 않음
if(!user){ // 로그인이 되어 있지 않으면 로그인 스크린으로 이동
return <Redirect href="/auth/login"/>;
}
return (
<SafeAreaProvider>
<TamaguiProvider config={config} defaultTheme="light">
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="modal" options={{ presentation: 'modal' }} />
</Stack>
</TamaguiProvider>
</SafeAreaProvider>
);
}
오류가 발생하는 이유는 expo-router에서 네비게이션이 작동하려면 Stack, Tabs등 라우터 컴포넌트가 먼저 렌더링되어 있어야 하는데 그렇지 않고 Redirect가 실행되었기 때문이다.
function RootLayoutNav() {
const { user, loading } = useAuth(); // useAuth 훅 사용
const router = useRouter(); // useRouter 훅 사용
if(loading) return null // 로딩 중이면 렌더링 하지 않음
if(!user){ // 로그인이 되어 있지 않으면 로그인 스크린으로 이동
return <Redirect href="/auth/login"/>;
}
return (
<SafeAreaProvider>
<TamaguiProvider config={config} defaultTheme="light">
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="modal" options={{ presentation: 'modal' }} />
</Stack>
</TamaguiProvider>
</SafeAreaProvider>
);
}
Stack이 준비 완료된 상태에서만 화면 전환이 가능하도록 코드를 작성한다.
useEffect(() => {
if (loaded && !loading) {
SplashScreen.hideAsync(); // 모든 준비 끝난 후 Splash 숨김
}
}, [loaded, loading]);
useEffect(() => {
if(!loading && loaded) {
if(user) {
router.replace('/(tabs)/(board)');
}else {
router.replace('/(auth)/login')
}
}
}, [user, loaded, loading])