블로그 목록

expo-image로 이미지 로딩 최적화하기 — 깜빡임과 캐시 문제 한 번에

리스트에 이미지가 많은 화면을 만들다 보면 항상 같은 문제에 부딪힌다. 스크롤할 때마다 이미지가 다시 로딩되면서 깜빡이고, 처음 뜰 때 흰 사각형이 잠깐 보이다가 툭 하고 나타난다. React Native 기본 Image 컴포넌트는 디스크 캐시가 제대로 안 돼서, 같은 URL을 다시 봐도 네트워크를 또 탄다.

이걸 라이브러리로 해결하려고 예전엔 react-native-fast-image를 많이 썼는데, 요즘 New Architecture로 넘어가면서 유지보수가 좀 애매해졌다. 그래서 Expo 프로젝트라면 expo-image가 사실상 정답이다. Expo 팀이 관리하고, New Architecture도 지원한다.

설치

npx expo install expo-image

기본 사용법

Imageexpo-image에서 가져오는 것만으로도 캐싱은 기본으로 켜진다. 여기에 몇 가지 prop만 얹으면 로딩 경험이 확 달라진다.

import { Image } from 'expo-image';

const blurhash = 'L6PZfSi_.AyE_3t7t7R**0o#DgR4';

function Thumbnail({ uri }: { uri: string }) {
  return (
    <Image
      style={{ width: 120, height: 120, borderRadius: 12 }}
      source={{ uri }}
      placeholder={{ blurhash }}
      contentFit="cover"
      transition={200}
      cachePolicy="memory-disk"
    />
  );
}

각 prop이 하는 일이 명확하다.

  • placeholder — 이미지가 로드되기 전에 보여줄 것. blurhash 문자열을 넣으면 흐릿한 미리보기가 뜬다. 흰 사각형 대신 실제 이미지의 색감이 미리 깔리니까 훨씬 자연스럽다.
  • transition — 로딩이 끝나면 몇 ms에 걸쳐 페이드인할지. 툭 튀어나오는 대신 부드럽게 나타난다.
  • contentFit — 웹의 object-fit과 같은 개념. cover, contain, fill 등.
  • cachePolicymemory-disk가 기본값이다. 메모리와 디스크 둘 다 캐싱하니 앱을 껐다 켜도 다시 안 받는다.

blurhash는 어디서 나오나

blurhash는 이미지를 20~30자 문자열로 압축한 값이다. 보통 서버에서 이미지를 업로드할 때 같이 생성해서 API 응답에 담아준다. 프론트에서 즉석으로 만들 수도 있지만, 리스트 아이템마다 계산하면 낭비라 미리 만들어두는 쪽이 낫다.

캐시 직접 비우기

프로필 이미지처럼 URL은 그대로인데 내용만 바뀌는 경우, 캐시 때문에 옛 이미지가 계속 보일 수 있다. 이럴 땐 명시적으로 비운다.

import { Image } from 'expo-image';

await Image.clearMemoryCache();
await Image.clearDiskCache();

정리하면, 기존 Imageexpo-image로 갈아끼우기만 해도 캐싱은 공짜로 얻는다. 거기에 placeholdertransition 두 줄만 추가하면 로딩 중 깜빡임이 사라진다. 리스트가 많은 앱이라면 체감 차이가 꽤 크다. blurhash까지 붙이면 데이터가 아직 안 왔는데도 화면이 이미 완성된 것처럼 보인다.