블로그 목록

expo-splash-screen으로 로딩 끝날 때까지 스플래시 붙잡기 — 흰 화면 깜빡임 없애기

앱을 켜면 스플래시가 뜨고, 사라지자마자 잠깐 흰 화면이 번쩍하더니, 그다음에야 폰트가 적용된 화면이 나타난다. 처음엔 못 봤는데 한 번 눈에 들어오니까 계속 거슬렸다.

원인은 단순했다. 스플래시는 네이티브가 알아서 앱 로딩이 끝나면 내려버리는데, 정작 내 앱은 그 시점에 커스텀 폰트도 아직 안 불러왔고 상태 복원도 안 끝난 상태였다. 스플래시가 너무 일찍 사라져서 준비 안 된 화면이 그대로 노출된 거다.

스플래시를 내가 내리도록 바꾸기

핵심은 두 개다. 앱이 뜨자마자 자동으로 내려가는 걸 막고(preventAutoHideAsync), 준비가 다 끝났을 때 내가 직접 내린다(hideAsync).

먼저 설치.

npx expo install expo-splash-screen

컴포넌트 바깥, 모듈 최상단에서 자동 숨김을 막아둔다. 여기서 호출해야 앱이 그려지기 전에 걸린다.

import * as SplashScreen from 'expo-splash-screen';
import { useFonts } from 'expo-font';
import { useCallback } from 'react';
import { View } from 'react-native';

// 모듈 로드 시점에 자동 숨김을 막는다
SplashScreen.preventAutoHideAsync();

export default function App() {
  const [fontsLoaded] = useFonts({
    Pretendard: require('./assets/Pretendard-Regular.otf'),
  });

  const onLayoutRootView = useCallback(() => {
    if (fontsLoaded) {
      // 첫 프레임이 그려진 직후 스플래시를 내린다
      SplashScreen.hideAsync();
    }
  }, [fontsLoaded]);

  if (!fontsLoaded) {
    // 아직 스플래시가 떠 있는 상태 — 아무것도 안 그려도 된다
    return null;
  }

  return (
    <View style={{ flex: 1 }} onLayout={onLayoutRootView}>
      {/* 실제 화면 */}
    </View>
  );
}

onLayout에서 내리는 이유

처음엔 useEffect에서 hideAsync를 불렀는데, 그러면 화면이 실제로 그려지기 전에 스플래시가 내려가서 또 흰 화면이 잠깐 보였다. onLayout은 루트 뷰가 화면에 배치된 뒤에 호출되니까, 첫 프레임이 준비된 걸 보장하고 나서 스플래시를 내릴 수 있다. 이 타이밍 차이가 깜빡임을 없애는 포인트였다.

페이드 아웃도 설정으로 준다

뚝 끊기는 게 싫으면 앱 설정에서 사라지는 애니메이션을 줄 수 있다.

// app.json
{
  "plugins": [
    ["expo-splash-screen", { "fadeDuration": 400 }]
  ]
}

Expo Router를 쓴다면 구조는 똑같다. App 대신 루트 app/_layout.tsx에서 preventAutoHideAsync를 걸고, 폰트가 준비되면 hideAsync를 부르면 된다.


결국 규칙은 하나다. 스플래시는 "앱 로딩"이 아니라 "내 준비"가 끝날 때 내려야 한다. preventAutoHideAsync로 붙잡고 onLayout에서 내리는 흐름만 잡아두면, 폰트든 원격 설정이든 로딩 대상이 뭐가 됐든 깜빡임 없이 자연스럽게 넘어간다.