ScrollView vs FlatList — 언제 무엇을 써야 하는가
ScrollView는 모든 자식을 한 번에 렌더링하고, FlatList는 보이는 것만 렌더링합니다. 이 차이가 성능에 결정적 영향을 미칩니다.
면접에서 "ScrollView와 FlatList의 차이"를 물으면 가상화(virtualization) 키워드를 중심으로 답하면 됩니다.
핵심 차이 한눈에
| 항목 | ScrollView | FlatList |
|---|---|---|
| 렌더링 | 모든 자식을 ** 즉시** 렌더링 | 보이는 영역만 ** 지연** 렌더링 |
| 데이터 | 정적 콘텐츠 | 동적 배열 데이터 |
| 성능 | 아이템 적을 때 좋음 | 아이템 많을 때 좋음 |
| 메모리 | 전체 콘텐츠만큼 사용 | 보이는 만큼만 사용 |
| 용도 | 폼, 설정, 고정 콘텐츠 | 피드, 목록, 검색 결과 |
ScrollView
import { ScrollView, View, Text, StyleSheet } from 'react-native';
function SettingsScreen() {
return (
<ScrollView
style={styles.container}
contentContainerStyle={styles.content}
showsVerticalScrollIndicator={false}
>
{/* 고정된 수의 UI 요소들 */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>계정</Text>
<SettingItem label="이름" value="심정훈" />
<SettingItem label="이메일" value="test@email.com" />
</View>
<View style={styles.section}>
<Text style={styles.sectionTitle}>알림</Text>
<SettingItem label="푸시 알림" />
<SettingItem label="이메일 알림" />
</View>
<View style={styles.section}>
<Text style={styles.sectionTitle}>기타</Text>
<SettingItem label="다크 모드" />
<SettingItem label="언어" value="한국어" />
<SettingItem label="앱 버전" value="1.0.0" />
</View>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
content: { padding: 20 },
section: { marginBottom: 24 },
sectionTitle: { fontSize: 18, fontWeight: 'bold', marginBottom: 12 },
});
ScrollView 유용한 속성
<ScrollView
// 스크롤 방향
horizontal={false}
// 스크롤 인디케이터
showsVerticalScrollIndicator={false}
// 페이징 (슬라이드 효과)
pagingEnabled
// 바운스 효과 (iOS)
bounces={true}
// 스크롤 이벤트
onScroll={(event) => {
const y = event.nativeEvent.contentOffset.y;
console.log('스크롤 위치:', y);
}}
scrollEventThrottle={16} // 16ms마다 이벤트 발생
// 키보드 처리
keyboardShouldPersistTaps="handled"
keyboardDismissMode="on-drag"
// 컨텐츠 최소 높이 (짧은 컨텐츠에서도 스크롤 영역 확보)
contentContainerStyle={{ flexGrow: 1 }}
/>
ScrollView를 쓰면 안 되는 경우
// 이렇게 하면 1000개 아이템이 모두 한 번에 렌더링됨 → 메모리 폭발
function BadExample() {
const data = Array.from({ length: 1000 }, (_, i) => `아이템 ${i}`);
return (
<ScrollView>
{data.map((item, index) => (
<View key={index} style={styles.item}>
<Text>{item}</Text>
</View>
))}
</ScrollView>
);
}
// FlatList로 변경하면 보이는 아이템만 렌더링
function GoodExample() {
const data = Array.from({ length: 1000 }, (_, i) => ({
id: String(i),
label: `아이템 ${i}`,
}));
return (
<FlatList
data={data}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<View style={styles.item}>
<Text>{item.label}</Text>
</View>
)}
/>
);
}
공부하다 보니 "아이템이 몇 개까지 ScrollView를 써도 괜찮나?"라는 질문이 많더라고요. 일반적으로 20~30개 이하 면 ScrollView가 괜찮고, 그 이상이면 FlatList를 쓰는 게 안전합니다.
FlatList가 적합한 경우
// 1. 서버에서 받아오는 동적 데이터
function FeedScreen() {
const [posts, setPosts] = useState<Post[]>([]);
return (
<FlatList
data={posts}
keyExtractor={(item) => item.id}
renderItem={({ item }) => <PostCard post={item} />}
onEndReached={loadMore}
onEndReachedThreshold={0.5}
/>
);
}
// 2. 검색 결과
function SearchResults({ results }: { results: SearchResult[] }) {
return (
<FlatList
data={results}
keyExtractor={(item) => item.id}
renderItem={({ item }) => <ResultItem result={item} />}
ListEmptyComponent={<Text>검색 결과가 없습니다</Text>}
/>
);
}
ScrollView + FlatList 조합
화면 상단에 고정 콘텐츠가 있고, 아래에 리스트가 있는 패턴입니다.
// 방법 1: FlatList의 ListHeaderComponent 사용 (권장)
function ProfileScreen() {
return (
<FlatList
data={posts}
keyExtractor={(item) => item.id}
renderItem={({ item }) => <PostCard post={item} />}
// 리스트 위에 고정 콘텐츠 배치
ListHeaderComponent={() => (
<>
<ProfileHeader />
<StatsSection />
<TabSelector />
</>
)}
/>
);
}
// 방법 2: ScrollView 안에 FlatList (비권장 — 성능 문제)
// 이렇게 하면 FlatList의 가상화가 무력화됨!
function BadCombination() {
return (
<ScrollView>
<HeaderSection />
{/* FlatList에 scrollEnabled={false}를 줘야 하므로 가상화 무의미 */}
<FlatList
data={data}
renderItem={renderItem}
scrollEnabled={false}
/>
</ScrollView>
);
}
ScrollView 안에 FlatList를 넣으면 경고가 뜨고 가상화가 제대로 동작하지 않습니다. 대신 FlatList의
ListHeaderComponent를 사용하세요.
성능 비교 실험
데이터 100개 기준:
┌──────────────────────────────────────┐
│ ScrollView │
│ - 초기 렌더링: 100개 전부 → 느림 │
│ - 메모리: ~50MB │
│ - 스크롤: 부드러움 │
├──────────────────────────────────────┤
│ FlatList │
│ - 초기 렌더링: 10개만 → 빠름 │
│ - 메모리: ~15MB │
│ - 스크롤: 부드러움 (설정에 따라) │
└──────────────────────────────────────┘
데이터 1000개 기준:
┌──────────────────────────────────────┐
│ ScrollView │
│ - 초기 렌더링: 1000개 → 매우 느림 │
│ - 메모리: ~200MB+ → 크래시 위험 │
│ - 스크롤: 버벅거림 │
├──────────────────────────────────────┤
│ FlatList │
│ - 초기 렌더링: 10개만 → 빠름 │
│ - 메모리: ~20MB (일정 유지) │
│ - 스크롤: 최적화 설정에 따라 부드러움│
└──────────────────────────────────────┘
판단 기준 체크리스트
- 아이템 수가 고정 이고 20개 이하 인가? → ScrollView
- 아이템 수가 가변 이거나 **많을 수 있는가 **? → FlatList
- 서버에서 데이터를 ** 페이지네이션 **으로 받는가? → FlatList
- ** 풀-투-리프레시 **가 필요한가? → FlatList (RefreshControl 지원)
- 폼이나 설정 화면처럼 ** 다양한 컴포넌트 혼합 **인가? → ScrollView
- 같은 형태의 아이템이 ** 반복 **되는가? → FlatList
정리
- ScrollView: 콘텐츠가 적고 고정적일 때 사용 (설정, 폼, 상세 화면)
- FlatList: 데이터가 많거나 동적일 때 사용 (피드, 검색, 목록)
- ScrollView 안에 FlatList를 넣지 마세요 —
ListHeaderComponent를 대신 사용 - 20~30개 이하 아이템은 ScrollView가 더 간단하고 충분합니다
- 면접 핵심: "FlatList는 가상화로 보이는 것만 렌더링하여 메모리와 성능을 확보한다"
댓글 로딩 중...