Kotlin Weekly

Kotlin Weekly # -380 "remember함수, derivedStateOf 활용"

베블렌 2023. 12. 12. 06:39

11월 2주차에는 derivedStateOf 의 활용에 대한 글입니다.

 

 

https://saurabharora.dev/posts/navigating-pitfalls-when-to-use-derivedStateOf-with-keys/

 

Navigating Pitfalls - When to Use derivedStateOf with remember(key) in Jetpack Compose

Jetpack Compose has transformed Android UI development by providing a straightforward approach to building user interfaces. One of its core principles is minimising unnecessary updates, and one of the tools it offers is derivedStateOf. In this blog post, w

saurabharora.dev

 

 

소개

이 글은 Jetpack Compose에서 derivedStateOf를 효과적으로 활용하는 방법과 그 사용시 발생할 수 있는 문제들을 해결하는 방법에 대한 글입니다. 해시태그 유효성 검사 예제를 통해 derivedStateOf의 사용과 잠재적인 문제점들을 설명해줍니다. 평소 상태관리할때 아무생각없이 remember쓰고 mutableStateOf 썼는데 조금더 자세한 과정을 알게된 글입니다. 

 

https://velog.io/@beokbeok/%EC%96%B8%EC%A0%9C-derivedStateOf%EB%A5%BC-%EC%8D%A8%EC%95%BC%ED%95%A0%EA%B9%8C

 

언제 derivedStateOf를 써야할까?

본 내용은 학습을 위해 Jetpack Compose — When should I use derivedStateOf? 을 보고 입맛대로 정리한 글입니다.

velog.io

이분 글이 정말 잘 정리되어있습니다. 기사보다도 잘 정리된글!

 

 

내용

1. derivedStateOf의 개념 및 해시태그 유효성 검사 예제

  • derivedStateOf는 상태나 키가 자주 변경되지만 특정 조건에서만 UI 재구성이 필요할 때 사용합니다.
  • 해시태그 유효성 검사 예제에서는 사용자가 해시태그를 입력하고, 유효하지 않은 경우 오류 메시지를 표시합니다.
@Composable
private fun PostHashtags(
    hashtags: ImmutableList<String>,
    onAddHashTag: (String) -> Unit,
    modifier: Modifier
) {
    var inputHashTag by remember { mutableStateOf("") }
    val isValidHashtag by remember(inputHashTag) {
        derivedStateOf { !inputHashTag.contains(" ") }
    }

    Column(modifier = modifier) {
        // OutlinedTextField와 다른 UI 요소들
    }
}

 

2. 예상치 못한 문제 및 로그 추가

  • 첫 해시태그 추가 후 오류 메시지가 표시되지 않는 문제 발생.
  • 로그를 추가하여 derivedStateOf 블록이 호출되지 않는 것을 확인.
val isValidHashtag by remember(inputHashTag) {
    derivedStateOf {
        Log.d("PostHashtags", "Calculating isValidHashtag")
        !inputHashTag.contains(" ")
    }
}

 

3. 문제의 근본 원인 및 해결 방법

  • remember 함수는 hashtags 목록이 변경될 때마다 inputHashTag의 새로운 값을 생성하고 기억합니다. 그러나 derivedStateOf는 이러한 변경을 감지하지 못합니다.
  • 해결책으로 remember를 inputHashTag 상태 객체로 키 설정하여, 새로운 상태 객체가 생성될 때마다 derivedStateOf가 이를 감지하도록 합니다.
val inputHashTag = remember(hashtags) { mutableStateOf("") }
val isValidHashtag by remember(inputHashTag) {
    derivedStateOf { !inputHashTag.value.contains(" ") }
}

 

 

4. 글에서의 총 정리 코드

@Composable
private fun PostHashtags(
    hashtags: ImmutableList<String>,
    onAddHashTag: (String) -> Unit,
    modifier: Modifier
) {
-   var inputHashTag by remember(hashtags) { mutableStateOf("") }
+   val inputHashTag = remember(hashtags) { mutableStateOf("") }
-   val isValidHashtag: Boolean by remember {
+   val isValidHashtag: Boolean by remember(inputHashTag) {
        derivedStateOf {
-           !inputHashTag.contains(" ")
+           !inputHashTag.value.contains(" ")
        }
    }

    Column(modifier = modifier) {
        OutlinedTextField(
-           value = inputHashTag,
+           value = inputHashTag.value,
-           onValueChange = { inputHashTag = it },
+           onValueChange = { inputHashTag.value = it },
            leadingIcon = { Text(text = "#", fontWeight = FontWeight.Bold) },
            placeholder = { Text(text = "Type a hashtag here") },
            trailingIcon = {
                AnimatedVisibility(
-                   visible = inputHashTag.isNotEmpty() && isValidHashtag,
+                   visible = inputHashTag.value.isNotEmpty() && isValidHashtag,
                    enter = fadeIn(),
                    exit = fadeOut()
                ) {
-                   IconButton(onClick = { onAddHashTag(inputHashTag) }) {
+                   IconButton(onClick = { onAddHashTag(inputHashTag.value) }) {
                        Icon(imageVector = Icons.Default.AddCircle,
                            contentDescription = "Add hashtag")
                    }
                }
            },
            isError = !isValidHashtag,
        )
        AnimatedVisibility(visible = !isValidHashtag) {
            Text(
                text = "Hashtag cannot have a space",
                style = MaterialTheme.typography.labelSmall,
                modifier = Modifier.padding(vertical = 2.dp)
            )
        }
        ReusableVerticalLazyList(content = hashtags)
    }
}

 

 

정리

derivedStateOf는 불필요한 재구성을 줄이는 데 매우 효과적인 도구지만 사용시 주의가 필요합니다. UI 업데이트의 시기와 방법을 제어하여 부드럽고 효율적인 사용자 경험을 보장할 수 있습니다. 신중하게 적용될 때, 더욱 성능이 좋고 반응이 빠른 애플리케이션을 만들 수 있습니다. 따라서 동적 UI 컴포넌트를 다룰 때 재구성을 최적화하고자 한다면 Jetpack Compose에서 derivedStateOf를 고려해보는 것이 좋습니다.

 

 

 
 

 

 

http://kotlinweekly.net/

 

** Kotlin Weekly **

 

kotlinweekly.net