[Compose Study] derivedStateOf
val result = remember(state1, state2) { calculation(state1, state2) }
val result1 = remember { derivedStateOf { calculation(state1, state2) } }
derivedStateOf
* 특정 상태가 계산되거나 다른 상태 개체에서 파생되는 경우 derivedStateOf를 사용한다.
derivedStateOf를 사용하면 계산에 사용된 상태 중 하나가 변경될 때마다 계산이 실행된다.
* TextField에 영어알파벳을 입력하면 true로 바뀌며, Submit버튼이 활성화 되는 코드이다.
* 처음에 u를 입력했을때 버튼이 활성화 된 이후로도 나머지 usernamed을 치는동안 불필요하게 버튼에 state를 보내고 있다.
var username by remember { mutableStateOf("") }
val submitEnabled = remember {
derivedStateOf {
isUsernameValid(username)
}
* derivedStateOf를 사용하면 위처럼 u에서 한번 상태가 활성화된 뒤, 더 이상 state를 보내지 않는다.
사용하는 예시
1. 스크롤이 경계값을 통과하는지 (scrollPosition > 0)
2. 리스트의 항목이 임계값보다 큰지 (아이템 > 0)
3. 위의 케이스와 같은 유효성 검사 (username.isValid())
FAQs
1. derivedStateOf는 remember를 사용해야 하는가?
- composable 함수 안에서는 사용해야 함
- derivedStateOf는 mutableStateOf 와 같이, recomposition이 일어나도 살아남아야 함
- remember하지 않으면, recomposition할 때마다 매번 재할당됨
2. remember(key) 와 derivedStateOf 차이
val result = remember(state1, state2) { calculation(state1, state2) }
val result1 = remember { derivedStateOf { calculation(state1, state2) } }
- recomposition의 횟수 차이
- remember(key)는 key가 변경되는 만큼 업데이트가 되어야 하는 경우
- key마다 다른 값 remember
ex) 사용자가 LazyColumn을 스크롤한 경우에만 버튼을 활성화하는 경우
val isEnabled = lazyListState.firstVisibileItemIndex > 0
* firstVisibleItemIndex는 사용자가 스크롤하여 변경될 때마다 독자가 recompose를 유도함에 따라 0, 1, 2 등이 변경된다.
우리는 firstVisibleItemIndex가 0보다 큰지 여부에만 관심이 있다.
우리가 필요로 하는 입력과 출력의 양에 차이가 있으므로 여기에서 derivedStateOf를 사용하여 불필요한 recomposition을
buffer out한다.
val isEnabled = remember {
derivedStateOf { lazyListState.firstVisibleItemIndex > 0 }
}
ex2) 매개 변수로 무언가를 계산하는 함수가 있다고 가정해보자.
우리는 해당 기능의 출력이 변경될 때마다 UI를 재구성하기를 원한다 (중요한 것은 해당 기능도 idempotent하다는 것이다).
여기서는 키 변경만큼이나 UI를 업데이트해야 하므로 키를 사용하여 기억한다.
즉, 입력과 출력의 양이 동일한 경우이다.
val output = remember(input) { expensiveCalculation(input) }
3. remember(key)와 derivedStateOf를 함께 사용하는 경우
@Composable
fun ScrollToTopButton(lazyListState: LazyListState, threshold: Int) {
// 버그 있음
val isEnabled by remember {
derivedStateOf { lazyListState.firstVisibleItemIndex > threshold }
}
Button(onClick = { }, enabled = isEnabled) {
Text("Scroll to top")
}
}
* 초기에 threshold = 0인 경우는 잘 동작함.
* 하지만 threshold가 변경되면, 조건(scrollPosition > threshold)이 맞지 않더라도 이전 값이 설정됨
* 이 때, threshold를 remember하게 되면, 변경될 때마다 state가 초기화 된다.
val isEnabled by remember(threshold) {
derivedStateOf { lazyListState.firstVisibleItemIndex > threshold }
}
-------------------
* 출처: https://medium.com/androiddevelopers/jetpack-compose-when-should-i-use-derivedstateof-63ce7954c11b
https://velog.io/@beokbeok/언제-derivedStateOf를-써야할까
'Study > Android' 카테고리의 다른 글
[Kotlin] TDD - 테스트 주도 개발 (0) | 2024.10.03 |
---|---|
[Compose Study] rememberCoroutineScope (0) | 2024.09.10 |
[Compose Study] Navigation (0) | 2024.09.09 |
[Compose Study] ViewModel에서의 상태 (1) | 2024.09.09 |
[Compose Study] State Hoisting (상태 호이스팅) (0) | 2024.09.08 |