Jetpack Compose에서 스크롤 가능한 리스트 UI를 구현할 때 Column + verticalScroll()과 LazyColumn 중 무엇을 선택해야 하는지 고민하는 경우가 많다. 결론부터 말하면, 리스트라면 대부분 LazyColumn이 더 적합하다.
1. Column + verticalScroll()의 동작 방식
Column에 verticalScroll()을 붙이면 전체 내용을 한 번에 모두 그린다.
즉,
- 화면에 보이지 않는 아이템까지 전부 compose 된다.
- 아이템 개수가 많아질수록 초기 렌더링 비용이 증가한다.
- 메모리 사용량이 커진다.
- 상태 변경 시 recomposition 범위가 커질 가능성이 있다.
아이템이 5~10개 정도로 매우 적다면 큰 차이는 없다. 하지만 20개 이상부터는 체감 차이가 생기기 시작한다.
이 구조는 “스크롤 가능한 레이아웃”이지, “대량 리스트 처리용 컴포넌트”는 아니다.
2. LazyColumn의 동작 방식
LazyColumn은 이름 그대로 lazy하게 동작한다.
- 화면에 보이는 아이템만 compose 한다.
- 스크롤 시 필요한 아이템만 새로 생성한다.
- 내부 구조는 RecyclerView와 유사한 방식이다.
아이템 수가 많을수록 Column과의 성능 차이는 크게 벌어진다. 특히 100개 이상에서는 사실상 LazyColumn이 필수라고 봐도 된다.
3. recomposition 관점에서의 차이
Column은 상태가 변경되면 전체 레이아웃이 다시 계산될 가능성이 크다.
반면 LazyColumn은 item 단위로 recomposition을 분리할 수 있다. 특히 key를 명확하게 지정하면 불필요한 재구성을 줄일 수 있다.
LazyColumn {
items(
items = list,
key = { it.id }
) { item ->
ItemView(item)
}
}
key를 지정하지 않으면 아이템 위치 기준으로 재사용이 이뤄져 의도하지 않은 recomposition이 발생할 수 있다. 실무에서는 거의 필수적으로 지정하는 것이 좋다.
4. 언제 무엇을 써야 하는가
Column + verticalScroll()이 적합한 경우
- 아이템 수가 매우 적은 경우
- 단순한 정적 화면 구성
- 리스트가 아니라 단순한 레이아웃 확장 목적
LazyColumn이 적합한 경우
- 서버 데이터 기반 리스트
- 아이템 개수가 20개 이상인 경우
- 페이징, 무한 스크롤
- 상태 변화가 자주 일어나는 리스트 UI
실무에서는 리스트 UI라면 거의 기본값처럼 LazyColumn을 사용한다고 보면 된다.
5. 정리
- 소량의 정적 콘텐츠라면
Column + verticalScroll()도 문제 없다. - 리스트 성격의 UI라면 처음부터
LazyColumn을 사용하는 것이 맞다. - 아이템이 늘어날 가능성이 있다면 애초에
LazyColumn으로 설계하는 것이 안전하다. - 성능, 메모리, recomposition 관리 측면에서
LazyColumn이 구조적으로 유리하다.
리스트 UI를 만든다면, 특별한 이유가 없는 한 LazyColumn을 선택하는 것이 올바른 판단이다.