derivedStateOf 사용하여 UI 업데이트

오리·2024년 12월 19일
0

문제사항

증상

mutableStateListOf로 사용자 리스트를 관리하고, 변경사항에 따라 UI가 리컴포지션되길 기대했지만

리스트 요소의 값 변경이 반영되지 않아 UI가 업데이트되지 않았음

원인

mutableStateListOf는 리스트의 구조적 변경(추가/삭제)만 감지함

즉, 리스트 내 개별 요소의 속성이 변경되더라도 이를 자동으로 감지하지 못하기 때문에 리컴포지션이 트리거되지 않음

해결

derivedStateOf를 사용하여 mutableStateListOf의 변화를 감지하고, UI를 올바르게 업데이트

list 안의 요소가 mutable state of 로 정의되어있기 때문에 derivedStateOf로 변화를 감지할 수 있었음.

mutableStateListOf 는 이 값 변경을 감지하지 못함 그래서 UI가 자동으로 리컴퍼지션 안됨

private var a = mutableStateListOf<User>()
private var b by mutableStateOf(User())
val list by derivedStateOf {
    a + b
  }

data class User(
  val user: User = User(),
  var isHungry: **MutableState<Boolean>** = mutableStateOf(false),
)

derivedStateOf

  • Jetpack Compose에서 파생 상태(derived state)를 정의할 때 사용
  • 파생 상태란, 기존 상태를 기반으로 새로 계산되는 상태를 의미
  • 다른 상태를 기반으로 파생된 값을 만들어 UI에서 쉽게 관찰
  • 상태 계산 로직을 효율적으로 관리, 불필요한 리컴포지션을 방지

예시

derivedStateOf 없이 매번 계산

val numbers = remember { mutableStateOf(listOf(1, 2, 3, 4, 5)) }
val evenNumbers = numbers.value.filter { it % 2 == 0 } // 호출 때마다 계산

LazyColumn {
    items(evenNumbers) { number -> Text("$number") }
}
  • 매번 filter를 다시 실행
  • 효율 낮음

derivedStateOf로 최적화

val numbers = remember { mutableStateOf(listOf(1, 2, 3, 4, 5)) }
val evenNumbers by derivedStateOf { numbers.value.filter { it % 2 == 0 } } // 상태 변경 시에만 계산

LazyColumn {
    items(evenNumbers) { number -> Text("$number") }
}
  • numbers.value가 변경될 때만 filter 실행
  • 불필요한 연산과 리컴포지션 방지
  • 값이 변하지 않으면 이전 결과를 재사용

주의점

  • 무거운 작업에 적합하지 않음
    • 가벼운 계산에 적합
    • 시간이 오래 걸리는 작업은 LaunchedEffect 또는 백그라운드 작업으로 처리하기
  • 상태 의존성을 명확하게
    • 파생 상태가 의존하는 상태를 명확히 지정하지 않으면 예기치 않은 결과가 발생할 수 있음

결론

  • derivedStateOf를 사용하면 특정 상태 변경에 따라 파생된 값을 효율적으로 관리하고, UI 업데이트를 제대로 반영할 수 있음.

0개의 댓글