Jetpack Compose를 사용하다 보면 상태(State)와 재구성(Recomposition)에 대해 자주 마주하게 됩니다. rememberUpdatedState
는 이러한 상태 관리에서 중요한 역할을 합니다. 공식 문서에 나와 있는 설명을 보면 다음과 같습니다.
reference a value in an effect that shouldn’t restart if the value changes
저는 이 설명이 처음에 잘 이해되지 않았습니다. 그래서 rememberUpdatedState
를 이해하기 위해 정리 겸 이 글을 쓰게 되었습니다. 이 글이 다른 사람에게 도움이 되기를 바랍니다.
예시 코드
다음은 rememberUpdatedState
를 설명하기 위해 공식 문서에서 사용된 샘플 코드입니다. LandingScreen
컴포저블은 최초 생성 후 일정 시간(SplashWaitTimeMillis
)이 지나면 onTimeout
함수를 호출하는 역할을 합니다.
중요한 요구사항은 LandingScreen
이 재구성 되더라도 딜레이는 늘어나면 안 된다는 점입니다.
1 |
|
위 코드에서 rememberUpdatedState
의 역할은 무엇일까요? rememberUpdatedState
를 사용하지 않고 onTimeout
을 LaunchedEffect
에서 사용하면 어떻게 될까요?
rememberUpdatedState 없이 사용하는 경우
LaunchedEffect
는 키가 true
로 설정되어 한번만 실행됩니다. 하지만 LandingScreen
은 onTimeout
이 변경될 때마다 재구성됩니다.
이때 LaunchedEffect
는 처음 실행될 때 캡쳐한 onTimeout
을 사용하기 때문에, LandingScreen
의 onTimeout
이 변경되어 재구성된 후에도 처음 받은 onTimeout
을 호출하게 됩니다.
1 |
|
LaunchedEffect의 키로 onTimeout을 사용하는 경우
LaunchedEffect
의 키로 onTimeout
을 사용하면, onTimeout
이 변경될 때마다 LaunchedEffect
가 재실행됩니다.
이렇게 하면 항상 최신의 onTimeout
이 호출되지만, LaunchedEffect
가 재실행될 때마다 delay(SplashWaitTimeMillis)
도 다시 시작되므로 딜레이 시간이 길어질 수 있습니다.
1 |
|
rememberUpdatedState의 역할
rememberUpdatedState
를 사용하면 LaunchedEffect
가 재실행되지 않으면서도 항상 최신의 onTimeout
을 참조할 수 있습니다. 이는 LaunchedEffect
가 재실행되지 않아 딜레이 시간이 유지되면서도, 최신 상태를 유지할 수 있게 합니다.
이제 아래의 rememberUpdatedState
에 대한 공식 문서의 한줄 설명이 이해가 되시나요?
reference a value in an effect that shouldn’t restart if the value changes
혹시 이 글이 다소 이해가 되지 않는다면 람다와 클로저, 그리고 이펙트에 대해 다시 학습해보면 도움이 되리라 생각합니다.
구현 보기
마지막으로 rememberUpdatedState
의 구현을 코드로 살펴봅시다.
rememberUpdatedState
는 아래와 같이 구현되어 있습니다. remember
에서 mutableStateOf(newValue)
를 통해 newValue
를 값으로 갖는 State
를 반환 합니다. 따라서 이렇게 반환된 State
는 리컴포지션이 발생하더라도 변경되지 않고 캐싱됩니다.
1 | fun <T> rememberUpdatedState(newValue: T): State<T> = remember { |
그리고 바로 apply { value = newValue }
를 통해 상태를 최신 값인 newValue
로 업데이트 합니다. 즉 이 구현은 상태 객체 자체는 유지하면서 값만 최신으로 업데이트하는 역할을 합니다. 이를 통해 최신 값을 항상 참조할 수 있습니다.