[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
Jetpack Compose — When should I use derivedStateOf?
derivedStateOf — a really common question we see is where and when is the correct place to use this API?
medium.com
https://velog.io/@beokbeok/언제-derivedStateOf를-써야할까
언제 derivedStateOf를 써야할까?
본 내용은 학습을 위해 Jetpack Compose — When should I use derivedStateOf? 을 보고 입맛대로 정리한 글입니다.
velog.io