최데브는 오늘도 프로그래밍을 한다.

컴포즈의 Side-Effect 형제들에 대해서 알아보자 - 1 본문

Android/Android Compose

컴포즈의 Side-Effect 형제들에 대해서 알아보자 - 1

최데브 2024. 4. 21. 15:00
반응형

컴포즈에는 side effect 라는 개념이 존재한다.

단어의 원래 뜻은 부작용이라는 뜻인데 왜 이런 명칭을 붙였는지 의아하긴 했는데

찾아보니 composable 은 단방향으로 state 를 전달하는게 기본인데 

전달되는 방향 반대로 상태를 변경해야하는 상황도 지원하기 위해

side effect 라는 개념을 도입했기 때문에 이런 이름이 붙었다고 한다.

요약을 해보자면 side effect 는 Composable 에서 자신이 아닌 외부의 상태에 영향을 발생시키는 것이겠다.

보통 flow 를 사용해서 특정 이벤트를 collect 하면 외부의 상태를 변경하는 경우가 일반적인 예라고 할 수 있겠다.

 

Side Effect 를 지원하기 위한 다양한 API

  • LaunchedEffect 
  • rememberCoroutineScope 
  • rememberUpdatedState 
  • DisposableEffect 
  • SideEffect 
  • produceState 
  • derivedStateOf 
  • snapshotFlow 

하나하나 순서대로 어떤 역할을 하고 어떨때 사용하면 좋을지 알아보자.

LaunchedEffect 

LaunchedEffect 는 컴포지션이 시작되면 바로 코루틴 블럭이 실행된다

LaunchedEffect (key = value){

 

}

이런식으로 key 를 등록하는데 키 key 의 값이 변경되면 실행중인 코루틴을 취소하고 새로운 코루틴을 시작한다.

true 로 넣는 경우에는 최초 한번 실행한다.

어떤 값이 변경될때마다 특정 동작을 실행시키고 싶다면 사용하기에 적합하다.

 

rememberCoroutineScope 

위에 LaunchedEffect 는 컴포저블의 생명주기와는 상관없이 실행될 수 있는데

rememberCoroutineScope 은 컴포저블 내부에서 실행할때 해당 컴포저블의 생명주기를 따른다.

그래서 리컴포저블이 일어날때마다 코루틴이 계속해서 생성되는것이 아니라

리컴포지션이 일어날때 취소가 되고 다시 실행 시킬 수 있는 상태가 된다.

val scope = rememberCoroutineScrop() //컴포저블 내부 적어주고 

Button (
  onClick = {
  	 //이렇게 쓰인다.
    scope.launch{
      
     }
  }
)

 

 

rememberUpdatedState 

이 경우는 예를 들어서 설명하는게 이해가 편하다.

 

일단  remeber 는 기본적으로 remember 의 value 값을 직접 수정 해주는것만으로 상태를 변화 시킬 수 있는데,

이렇게 말을 하는 이유는

하위 컴포저블의 상위 컴포저블에서 하위컴포저블로 remember 값을 주입할때는 그냥 주입만 해서는 업데이트가

되지 않기 때문에 상위에서 받은 데이터를 하위에서 직접 넣어줘야만 상태가 변화된다는 말이다.

이런  한계점은 아래 케이스에서 볼 수 있다.

 

문제의 케이스

       var text by remember { mutableStateOf("zzz") }
            Column {
                OutlinedTextField(
                    value = text,
                    onValueChange = {text = it}
                )
                TextData(input = text)
            }
        }

 

//상위 컴포저블의 remember 값을 하위 컴포저블인 TextData 에서 주입 받는중
//값의 상태가 생각한대로 바뀌지 않는다.
@Composable
fun TextData(input : String){
    val rememberInput by remember { mutableStateOf(input) }
    Text(text = "remeberInpput :$rememberInput")
}

 

실행시켜서 입력창에 값을 넣어도 rememberInput 의 데이터가 변하지 않는걸 볼 수 있다.

바뀌게 보여주려면 위에 말한것 처럼  remember 의 value 값을 직접 수정해야한다.

아래 처럼 말이다.

@Composable
fun TextData(input : String){
    val rememberInput by remember { mutableStateOf(input) }.apply {
        value = input
    }
    Text(text = "remeberInpput :$rememberInput")
}

 

안되는건 아니지만 꽤나 귀찮지 않을까? 또 생각도 못한 문제가 발생 할 수도 있다. 

이걸 한번에 동작하게 해주는게 rememberUpdatedState  다.

내부 코드를 까보면 위 코드 동작을 구현해놓은걸 아래처럼 확인해 볼 수 있다.

@Composable
fun <T> rememberUpdatedState(newValue: T): State<T> = remember {
    mutableStateOf(newValue)
}.apply { value = newValue }

 

사용하는건 아래처럼 사용하면 된다.

@Composable
fun TextData(input : String){
    val rememberedUpdateInput by rememberUpdatedState (input)
    Text(text = "remeberInpput :$rememberedUpdateInput")
}

 

 

글이 길어질 것 같아서 

  • DisposableEffect 

부터는 다음글로 나눠서 작성하겠다.

반응형
Comments