Side Effect란 무엇인가?
Side Effect(부수 효과)란 Composable 범위 밖에서 발생하는 앱 상태에 대한 변경이다.
Side Effect를 이해하기 위해서는 아래 두가지를 이해해야 한다.
- Composable은 각각의 Lifecycle을 가지고 있다.
- Composable은 단방향으로만 State를 전달한다.
우리는 Composable을 사용할 때 여러 Composable들을 겹쳐서 사용한다. 그러면 시스템은 각 Composable에 대한 Lifecycle을 만들고, Composable 별로 재구성이 필요할 때만 재구성시킨다. 또한 Composable은 기본적으로 바깥쪽 Composable이 안쪽 Composable로 State를 내려준다. 이로 인해 단방향으로만 의존성이 생긴다. 하지만 만약 안쪽에 있는 Composable에서 바깥쪽에 있는 Composable의 상태에 대한 변경을 준다면? 혹은 Composable에서 Composable이 아닌 앱 상태에 대한 변화를 준다면? 양방향 의존성으로 인해 예측할 수 없는 Effect(효과)가 생길 것이다. 우리는 이를 Side Effect라 부른다.
Side Effect란 Composable에서 자신이 아닌 외부의 State(상태)에 영향을 만드는 것을 뜻한다.
함수형 프로그래밍에서 부수효과는 함수에서 참조하는 변수가 외부에 있어서 변화할 수 있을 때(Mutable) 생긴다. 즉, 부수효과(Side Effect)는 외부의 State에 의존하게 될 때 생긴다.
Side Effect의 예시
예를 들어 우리가 메모 리스트를 표현하는 Screen과 메모를 작성하는 Screen 두가지 Screen으로 이루어진 메모장 앱을 만든다고 하자. 메모를 작성하는 Screen에서 저장하기 버튼를 눌렀을 때 navigation은 메모 리스트 Screen으로 이동해 작성된 메모를 보여주어야 한다. 하지만, 저장하기 버튼 Composable은 navigation에 대한 참조가 없다. 따라서 Button Composable은 이러한 이벤트가 발생되면 외부의 navigation에 대한 변화를 만들어야 한다. 이러한 변화를 바로 부수효과라 한다.
LaunchedEffect(scope) {
viewModel.eventFlow.collectLatest { event ->
when(event) {
is AddNoteScreenEvent.SaveNote -> {
navController.navigateUp()
}
}
}
}
Side Effect 처리하기
Compose는 이러한 Side Effect(부수효과)를 처리하기 위한 다양한 Effect API를 제공한다. 우리는 Compose에서 Side Effect를 처리하기 위해 다음 동작을 실행할 수 있는 Effect API를 사용할 수 있다.
- LaunchedEffect : Composable Lifecycle Scope에서 suspend fun 실행하기 위해 사용
- DisposableEffect : Composable이 Dispose될 때 정리되어야 할 Side Effect 정의하기 위해 사용
- SideEffect : Compose의 State을 Compose에서 관리하지 않는 객체와 공유하기 위해 사용
추가적으로 Compose는 위 3가지와 함께 사용할 수 있는 여러 CoroutineScope과 State관련 함수를 제공한다.
- rememberCoroutineScope : Composable의 CoroutineScope을 참조하여 외부에서 실행할 수 있도록 함
- rememberUpdatedState : Launched Effect는 컴포저블의 State가 변경되면 재실행되는데 재실행 되지 않아도 되는 State를 정의하기 위해 사용
- produceState : Compose State가 아닌것을 Compose의 State로 변환
- derivedStateOf : State를 다른 State로 변환하기 위해 사용 Composable은 변환된 State에만 영향 받음
- snapshotFlow : Composable의 State를 Flow로 변환