[Jetpack Compose] rememberUpdatedState 에 대해서 알아보자 !

오규성·2025년 11월 7일

Jetpack Compose 기초

목록 보기
6/13
post-thumbnail

# rememberUpdatedState 란?

상태 객체를 생성하고 매 컴포지션마다 값을 업데이트하여 최신화하는 함수

@Composable
fun <T> rememberUpdatedState(newValue: T): State<T> = remember {
    mutableStateOf(newValue)
}.apply { value = newValue }

# 이게 왜 필요할까?

이름과 설명만 보면 remember { mutableStateOf } 도 있고, 참조한 상태가 변했을때만 계산하는 derivedStateOf 도 존재하는데 왜 이걸 사용할까 의문이 들 수도 있다.

하지만 함수가 있는 것에는 다 이유가 있는법.

우선 derivedStateOf 의 경우 N 개의 상태를 통해 새로운 상태를 파생 하므로 이 함수의 목적과는 다르다.
그나마 비슷한 것은 remember { mutableStateOf() } 인데 언뜻보면 이 둘은 서로 같다고 볼 수 있으나, 사용 방법은 아예 다르다.

예시를 하나 들어보자.

우리는 버튼을 눌러 count 를 1씩 올리고, Child 에서 이 값이 2로 나눠지면 Text 에 Boolean 값을 보여주려고 한다.

이것을 코드로 나타내면 다음과 같다.

class MainActivity() : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            enableEdgeToEdge()

            MaterialTheme {
                Scaffold {
                    Column(modifier = Modifier
                        .fillMaxSize()
                        .padding(it)
                    ) {
                        var count by remember { mutableStateOf(1) }

                        Child(count)
                        Button({ count++ }) { }
                    }
                }
            }
        }
    }
}

@Composable
fun Child(count: Int){
    val isEven by remember(count) { mutableStateOf(count % 2 == 0) }

    Text(text = isEven.toString())
    
}

Child 에서 받는 count 는 순수한 값 자체이므로 key 를 지정해주지 않으면 isEven 은 리컴포지션 시에도 inValid 가 false 가 되어 재계산이 진행되지 않는다.

그렇기에 우리는 key 에 count 를 넣어줬는데, 이렇게 되면 count 가 변화할 때마다 mutableStateOf 함수가 실행되어 새로운 State 인스턴스를 생성한다.

만약 count 가 1만번 증가했다면 1만번의 새로운 인스턴스가 생성되는 것이다.
그런데 만약 위의 코드에서 변화가 생겨 다음과 같이 LaunchedEffect 를 사용한다고 생각해보자.

@Composable
fun Child(count: Int){
    val isEven by remember(count) { mutableStateOf(count % 2 == 0) }
    
    Text(text = isEven.toString())
    
    LaunchedEffect(Unit) {
        while (true){
            delay(500L)
            Timber.d("확인 - ${isEven}")
        }
    }
}

LaunchedEffect 의 경우 key 가 변경되지 않으면 내부 코루틴은 재시작하지 않는다.

그런데 만약 이전에 말한것처럼 remember 의 key 바뀌어 새 인스턴스가 생성된다면 어떻게 될까?

LaunchedEffect 가 바라보는 State Instance 와 현재 State Instance 가 다르기 때문에 값의 추적이 불가능해진다.

이럴 때 다음과 같이 수정해준다면 값을 최신화하여도 추적이 가능해진다.

@Composable
fun Child(count: Int){
    val isEven by rememberUpdatedState(count % 2 == 0)

    Text(text = isEven.toString())

    LaunchedEffect(Unit) {
        while (true){
            delay(500L)
            Timber.d("확인 - ${isEven}")
        }
    }
}

이게 가능한 이유는 rememberUpdatedState 가 내부적으로

remember {
    mutableStateOf(newValue)
}.apply { value = newValue }

와 같이 key 를 지정하지 않는, 기존 인스턴스에 대한 값 업데이트만을 진행하기 때문이다.

그렇다고 막 쓰지는 말자.

매우 편리해보일 수 있으나, 이것은 변수를 읽기 상태로 만들어줘야하고, 내부 코드가 remember { mutableStateOf }.apply { value = newValue } 이기 때문에 매 컴포지션 (함수 호출) 이 발생할 때마다 계산식이 이루어지므로 매우 복잡한 계산식이 사용된다면 이를 권장하지 않는다.

profile
안드로이드 개발자 Gyu 의 개발 블로그 !

0개의 댓글