
Jetpack Compose remember는 Compose 상태 관리에서 가장 먼저 만나는 함수입니다. recomposition이 일어나도 값이 계속 남아 있는 것처럼 보이지만, 어디까지 기억하는지 모르면 화면 회전이나 상태 위치에서 쉽게 헷갈립니다.
핵심은 remember가 같은 composable 위치에서 값을 재사용하게 해 주지만 앱 상태를 영구 보관하는 장치는 아니라는 점입니다. 이 글은 Android Developers의 Compose state 문서를 기준으로 remember, mutableStateOf, rememberSaveable, 상태 호이스팅을 정리합니다.

Jetpack Compose remember를 먼저 한 줄로 정리하면
`remember`는 composable이 recomposition될 때 이전에 계산한 값을 다시 사용할 수 있게 해 주는 함수입니다. 같은 위치의 composable이 composition에 남아 있는 동안 값을 기억합니다.
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("count: $count")
}
}버튼을 누르면 count가 바뀌고, Compose는 이 값을 읽는 UI를 다시 그릴 수 있습니다. 이때 `remember`가 없으면 recomposition 때마다 초기값으로 돌아갈 수 있습니다.
recomposition이 일어나도 왜 값이 남을까
Compose는 UI를 함수처럼 다시 호출할 수 있습니다. recomposition은 화면 전체를 무조건 새로 만드는 일이 아니라, 상태 변경에 따라 필요한 composable을 다시 실행하는 과정입니다.
`remember`는 이 재실행 사이에서 값을 저장해 둡니다. 그래서 같은 composable 위치에서 다시 실행되면 새로 계산하지 않고 이전 값을 재사용합니다.
remember와 mutableStateOf는 역할이 다르다
`remember`는 값을 보관합니다. `mutableStateOf`는 Compose가 관찰할 수 있는 state holder를 만듭니다. 둘을 함께 쓰는 이유는 값을 기억하면서, 값이 바뀔 때 UI 갱신도 일어나게 하기 위해서입니다.
val textState = remember { mutableStateOf("") }
TextField(
value = textState.value,
onValueChange = { textState.value = it }
)단순히 계산 비용이 큰 객체를 기억할 때는 `remember`만 의미가 있을 수 있지만, 화면에 영향을 주는 값이라면 관찰 가능한 상태인지 함께 봐야 합니다.
remember는 어디까지 기억할까
remember는 composition 안에서 값을 보관합니다. 하지만 화면 회전, 프로세스 재생성, navigation back stack, ViewModel 생명주기까지 모두 해결하는 저장소는 아닙니다.
- 단순 recomposition 사이에서 유지: remember
- configuration change 일부까지 저장: rememberSaveable
- 화면 비즈니스 상태와 비동기 작업 관리: ViewModel
- 앱을 껐다 켜도 남아야 하는 데이터: DataStore, Room, 서버 저장소
rememberSaveable은 언제 필요할까
입력창 값처럼 화면 회전 후에도 자연스럽게 남아야 하는 작은 UI 상태는 `rememberSaveable`을 검토할 수 있습니다. 내부적으로 저장 가능한 형태여야 하며, 복잡한 객체는 Saver가 필요할 수 있습니다.
@Composable
fun SearchBox() {
var query by rememberSaveable { mutableStateOf("") }
TextField(
value = query,
onValueChange = { query = it }
)
}반대로 서버에서 다시 불러와야 하는 데이터, 여러 composable이 공유하는 상태, 화면 생명주기와 연결된 작업은 ViewModel 쪽이 더 자연스러운 경우가 많습니다.
상태 호이스팅으로 remember 위치를 정한다
상태를 composable 내부에 둘지, 호출자 쪽으로 올릴지는 재사용성과 제어권의 문제입니다. TextField처럼 값과 변경 이벤트를 밖으로 열어두면 더 테스트하기 쉽고 조합하기 쉬운 composable이 됩니다.
@Composable
fun NameField(
name: String,
onNameChange: (String) -> Unit
) {
TextField(
value = name,
onValueChange = onNameChange
)
}remember를 어디에 둘지는 이 상태를 누가 소유해야 하는지에 대한 설계 결정입니다. 단순 UI 내부 상태라면 안쪽에 두고, 화면 전체가 알아야 하면 위로 올립니다.
자주 하는 실수
- remember를 쓰면 화면 회전 후에도 항상 남는다고 생각한다
- ViewModel에 있어야 할 비즈니스 상태를 composable 내부 remember에만 둔다
- 리스트 item에서 key 없이 상태를 기억해 스크롤이나 순서 변경 때 값이 섞인다
- 상태 값을 바꾸지만 Compose가 관찰하지 못하는 일반 변수에 저장한다
실무 체크리스트
- 값이 recomposition 사이에서만 유지되면 remember를 사용한다
- 값 변경이 UI를 다시 그려야 하면 mutableStateOf 같은 observable state를 사용한다
- 화면 회전 후에도 필요한 작은 UI 값이면 rememberSaveable을 검토한다
- 화면의 핵심 상태와 비동기 작업은 ViewModel로 올린다
- 재사용 composable은 value와 onValueChange를 받아 상태를 호이스팅한다
정리
Jetpack Compose remember를 이해할 때는 문법 이름보다 문제를 일으키는 지점을 먼저 봐야 합니다. 오늘 글의 핵심은 겉으로 비슷해 보이는 코드가 어떤 기준으로 다르게 동작하는지 분리해 보는 것입니다.
함께 보면 좋은 내부 글은 collectAsStateWithLifecycle 사용 기준, Compose 상태 호이스팅은 언제 해야 할까, Jetpack Compose remember와 rememberSaveable 차이입니다. 외부 기준은 Android Developers – State and Jetpack Compose, Android Developers – State hoisting, Android Developers – Lifecycle of composables를 확인했습니다.