React Native에서 Lottie 사용하기 — lottie-react-native 실전 가이드
React Native에서 Lottie를 쓰는 표준은 lottie-react-native입니다. 내부적으로 iOS는 lottie-ios, Android는 lottie-android를 감싸므로 네이티브 수준의 렌더링 성능을 그대로 얻습니다.
설치
npm install lottie-react-native
# iOS는 pod 설치 필요
cd ios && pod install
Expo 프로젝트라면 더 간단합니다.
npx expo install lottie-react-native
기본 사용
import LottieView from "lottie-react-native";
export default function Loading() {
return (
<LottieView
source={require("./assets/loading.json")}
autoPlay
loop
style={{ width: 120, height: 120 }}
/>
);
}
원격 URL도 지원하지만(source={{uri: "..."}}), 첫 화면 에셋은 네트워크 지연이 없도록 번들에 포함하는 것을 권장합니다.
ref로 재생 제어
const animationRef = useRef<LottieView>(null);
// 특정 구간만 재생
animationRef.current?.play(0, 45);
// 리셋
animationRef.current?.reset();
<LottieView
ref={animationRef}
source={require("./assets/success.json")}
loop={false}
onAnimationFinish={() => console.log("done")}
/>
진행률 바인딩 — 제스처 연동
progress prop에 Animated 값을 연결하면 스크롤·제스처에 애니메이션을 동기화할 수 있습니다.
const progress = useRef(new Animated.Value(0)).current;
<LottieView source={require("./assets/pull.json")} progress={progress} />
// 스크롤 오프셋 → 0~1 진행률로 매핑
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: scrollY } } }],
{ useNativeDriver: false }
)}
실무 주의점
- New Architecture(Fabric) — 최신 버전은 Fabric을 지원하지만, 구버전 조합에서 빈 화면이 나오는 이슈가 있습니다. RN 버전과 라이브러리 버전 호환 표를 확인하세요.
- iOS/Android 렌더링 차이 — 양 플랫폼이 서로 다른 네이티브 구현을 쓰므로 같은 파일이 다르게 보일 수 있습니다. 특히 블렌드 모드·매트가 걸린 파일은 양쪽 다 확인해야 합니다.
- 리스트 안에서의 사용 — FlatList 셀마다 autoPlay를 걸면 저사양 Android에서 스크롤이 급격히 무거워집니다. 보이는 셀만 재생하도록 viewability를 연동하세요.
- 에셋 검수 먼저 — 통합 전에 Lottie Inspector로 파일 크기·레이어 수를 확인하면 성능 문제의 절반은 예방됩니다.
New Architecture에서 빈 화면이 뜰 때
제 프로젝트에서 React Native를 0.74로 올리며 New Architecture를 켰을 때, 에러 한 줄 없이 Lottie가 있어야 할 자리만 빈 채로 렌더링되는 문제를 겪었습니다. 크래시가 나면 스택 트레이스라도 있으니 원인을 좁히기 쉬운데, 이 경우는 뷰가 조용히 사라지기만 해서 처음에는 JSON 파일이 깨진 줄 알고 엉뚱한 곳을 한참 뒤졌습니다.
원인은 파일이 아니라 라이브러리 버전이었습니다. lottie-react-native 5.x까지는 구 아키텍처의 뷰 등록 방식만 지원하기 때문에, Fabric이 활성화된 앱에서는 네이티브 컴포넌트를 찾지 못하고 빈 뷰를 그립니다. 6.0부터 Fabric 대응이 들어갔으므로, Fabric 환경에서 빈 화면을 만나면 코드보다 버전부터 의심하는 쪽이 빠릅니다. 제가 쓰는 확인 순서는 이렇습니다.
- 1. 아키텍처 상태 확인 — Android는
gradle.properties의newArchEnabled=true여부, iOS는pod install로그에 New Architecture 활성 메시지가 찍히는지 봅니다. 켠 기억이 없어도 템플릿 업그레이드 과정에서 함께 켜진 경우가 있습니다. - 2. 실제 설치 버전 확인 —
npm ls lottie-react-native로 확인합니다. package.json에 적힌 범위와 실제 설치된 버전이 다른 경우가 의외로 많습니다. - 3. 네이티브 재빌드 — 버전을 올렸다면
pod install을 다시 실행하고 클린 빌드까지 해야 합니다. JS 번들 리로드만으로는 절대 반영되지 않습니다. - 4. 임시 회피 — 당장 라이브러리를 올리기 어렵다면
newArchEnabled를 꺼서 구 아키텍처로 되돌리는 것도 릴리즈 일정을 지키는 현실적인 선택입니다.
RN ↔ lottie-react-native 버전 호환 가이드
제가 실무에서 참고하는 대략적인 조합입니다. 마이너 버전 단위로 세부 사항이 달라지므로, 최종 확인은 반드시 공식 저장소의 README와 릴리즈 노트로 하시기 바랍니다.
| lottie-react-native | React Native | New Architecture |
|---|---|---|
| 5.x | 0.64 ~ 0.70 부근 | 미지원 — 구 아키텍처 전용 |
| 6.x | 0.71 이상 권장 | 지원 시작 — Fabric 대응 포함 |
| 7.x | 0.75 이상 권장 | 지원 — New Architecture 기본 활성 세대 |
자주 겪는 에러와 해결
제가 실제로 부딪힌 순서대로 정리했습니다. 셋 다 라이브러리 자체의 버그가 아니라 통합 과정의 실수라서, 알고 나면 허무하지만 모르면 시간을 꽤 잡아먹습니다.
requireNativeComponent를 찾을 수 없다는 에러
npm install 직후 iOS에서 가장 먼저 만나는 에러입니다. 원인은 대부분 pod install 누락입니다. JS 패키지만 설치하고 네이티브 의존성을 연결하지 않은 상태라서, cd ios && pod install 후 앱을 완전히 다시 빌드해야 합니다. Metro 재시작만으로는 해결되지 않습니다. 네이티브 모듈을 추가하면 재빌드가 필요하다는 걸 알면서도, 급할 때는 저도 자꾸 빼먹는 단계입니다.
JSON을 교체했는데 이전 애니메이션이 나올 때
디자이너에게 수정본을 받아 같은 파일명으로 덮어썼는데 화면에는 여전히 이전 버전이 나오는 경우가 있습니다. Metro 번들러가 에셋을 캐시하고 있어서 생기는 문제로, npx react-native start --reset-cache로 캐시를 비우면 해결됩니다. 저는 이 문제로 한 번 헤맨 뒤로는 수정본을 받으면 교체 전에 뷰어에서 파일을 먼저 열어 정말 바뀐 파일이 맞는지부터 확인합니다.
require 경로에 변수를 쓸 수 없는 문제
require는 번들 단계에서 정적으로 분석되기 때문에 경로에 변수를 넣으면 실패합니다. 조건에 따라 다른 애니메이션을 보여줘야 한다면 가능한 조합을 미리 정적으로 매핑해 두는 방식으로 우회합니다.
// 이렇게는 동작하지 않습니다
// require(`./assets/${name}.json`)
// 정적 매핑으로 우회
const animations = {
success: require("./assets/success.json"),
error: require("./assets/error.json"),
};
<LottieView source={animations[status]} autoPlay loop={false} />