본문 바로가기
Jetpack Compose

[Jetpack Compose] 단방향 데이터 흐름 UDF(Unidirectional Data Flow) 살펴보기

by JongSeok 2023. 12. 29.

Jetpack Compose에서 기본적으로 UI는 수정될 수 없습니다.

UI는 상태(State)에 따라서 존재하고, 상태가 변경되는 경우에 변경된 UI 트리에 맞춰 다시 UI를 그리게 됩니다.

 

Compose에서 UI를 다시 그리는 과정을 Recomposition이라고 하고, compose에서 UI 갱신은 오직 Recomposition에 의해서만 이루어집니다.


@Composable
fun OutlinedTextFieldEx() {
    var name by remember { mutableStateOf("") }
    
    OutlinedTextField(
        value = name,
        onValueChange = {
            name = it
        }
    )
}

위의 예시에서 OutlinedTextField는 내부에서 상태를 가지고 있지 않습니다.

상태는 외부의 name이 String 타입의 상태를 가지고 있고, 그 상태를 OutlinedTextField의 value를 통해 UI에 보여주고 있습니다.

 

OutlinedTextField의 값이 수정되면 OutlinedTextField 내부에는 상태를 갖지 않기 때문에 상태를 갖는 name에 onValueChange를 이용해 변경된 값을 할당하고, name의 상태가 변경되었기 때문에 OutlinedTextField 값도 변경되는 형태를 띄게 됩니다.

Jetpack Compose로 개발을 하다보면 여러 @Composable 함수를 중첩해 UI를 구성하게 됩니다.

 

이때, @Composable 함수를 구성하는 데이터의 흐름은 상태는(State) 하위로 내려보내고, 이벤트(Event)는 상위로 올려 보내는 단방향성 구조를 갖습니다.

상태는 상위 컴포저블 함수 혹은 ViewModel에서 관리하고, 하위 컴포저블 함수에서는 상태를 직접 다루지 않고 상위 컴포저블의 상태에 따른 UI 갱신만을 수행하도록 작성된 코드가 좀 더 효율적이라고 할 수 있을 것 같습니다.

 

@Composable
fun OutlinedTextFieldEx(name: String, onNameChanged: (String) -> Unit) {    
    OutlinedTextField(
        value = name,
        onValueChange = onNameChanged
    )
}

name의 상태를 OutlinedTextFieldEx 컴포저블 함수에서 관리하던 샘플을
value와 onValueChange를 상위 컴포저블 함수로 부터 매개변수로 전달받는 방식의 코드로 개선할 수 있습니다.

 

해당 샘플에서 name의 상태를 할당하는 value는 상위에서 하위로 내려받고, onValueChange가 발생할 때 onNameChanged 람다식을 이용해 하위에서 상위로 올려 보내는 단방향성 구조를 갖는 것을 볼 수 있습니다.

 

단방향성 데이터 흐름을 유지할 때의 장점은 다음과 같습니다.

  • 테스트 가능성: 상태를 표시하는 UI와 상태를 분리해 테스트하기 용이합니다.
  • 상태 캡슐화: 상태가 한 곳에서만 갱신될 수 있으면, 컴포저블 상태를 위한 단일 정보 진실원(SSOT, single source of truth)가 될 수 있고, 일관되지 않는 상태로 인해 발생하는 버그를 줄일 수 있습니다.
  • UI 일관성: StateFlow와 LiveData 같은 관측가능한 상태 홀더를 사용해 UI 상태 갱신을 즉각 반영할 수 있습니다.

 

728x90
반응형