특정 화면에 접속했을 때, 서버로 부터 데이터를 받아와야 했다.
이런 초기 데이터는 아래와 같이 Composable Function 내부에서 구현했다.
fun TestScreen() {
LaunchedEffect(key1 = Unit) {
viewModel.initLoad()
}
// 나머지 화면 구성...
}
이 코드의 단점은… onDestroy가 호출된다면, 반드시 다시 실행된다는 점이다..
예를 들어 화면이 전환되었거나, 다크 모드로 변경할 때마다 load함수를 재호출하게 된다.
만약 데이터의 동기화가 중요한 서비스라면 이해할 수 있지만, 우리 서비스는 그 정도의 동기화를 필요로 하지 않았다. 오히려 저런 구성 변경에 대해 서버로 재요청하지 않기를 바랬다. 돈없는 작은 서버니까…
여러 검색을 해본 결과 이 고민을 나만 하는 것이 아니라는 것을 알 수 있었다. 가장 많이 나오는 예시이자, 약간의 논란이 있는 ViewModel의 Init 블럭이다.
@HiltViewModel
class MapViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
private val getMapInfoUseCase: GetMapInfoUseCase,
private val getStoreInfoUseCase: GetStoreInfoUseCase,
) : BaseViewModel<MapUiState, MapEvent, MapEffect>(savedStateHandle) {
init {
// 초기 로드 함수 호출
initLoad()
}
// 그 외...
}
이 경우 ViewModel이 살아있는 동안 단 1회만 호출하는 방식이므로 서버로의 요청은 1회만 한다는 장점을 가진다.
이러한 코드의 단점으로는 ViewModel의 생명주기에 맞게 데이터를 호출한다는 점이다.
초기 데이터를 호출하는 이유는, 사용자가 그 화면에 처음 들어왔기 때문인데, ViewModel이 생성되었기 때문에 load를 한다는건 다른 SideEffect를 발행할 수 있다. (이에 대한 엣지 케이스는 찾지 못하였다.)
두번째로 테스트 코드 작성에 대한 문제점이다.
테스트 코드를 작성할 때 ViewModel에 대한 테스트가 있을 텐데, ViewModel을 생성할 때마다 불필요하게 (강제적으로) 서버로 데이터를 전송하게 되는 문제가 존재한다.