[Expo] [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]

Hayden·2025년 4월 18일

[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])
profile
백엔드 공부

0개의 댓글