0. ViewModel의 정의

Android 에서 상태를 저장하고 관리하기 위해 사용되는 전형적인 수단


1. 잘못된 용례

// BAD
@Composable
fun LoginScreen() {
    **val viewModel: LoginViewModel = hiltViewModel() <- 이 부분**
    val state = viewModel.state
    Column {
        if (state.isLoading) {
            CircularProgressIndicator()
        }
        Button(onClick = { viewModel.login() }) {
            Text(text = "Login")
        }
    }
}

뷰모델이 Screen의 생성자에 주입되고 있음. 이러한 방식은 하기 단점이 존재.


1. 올바른 용례

// GOOD
sealed interface LoginEvent {
    object Login: LoginEvent
    // More events...
}
/**
 * 각각의 ViewModel은 Screen 의 State 객체를 가지고 있음.
 */
class LoginViewModel: ViewModel() {

    **var state by mutableStateOf(LoginState())** <- LoginScreen의 State
        private set

    fun onEvent(event: LoginEvent) {
        when(event) {
            is LoginEvent.login -> { /* Handle login */ }
            // ,,,
        }
    }
}

---
/**
 * Screen을 래핑하는 Composable. 이 곳에서 ViewModel을 안전하게 초기화.
 */
@Composable
fun LoginScreenRoot() {
    val viewModel = hiltViewModel<LoginViewModel>()
    LoginScreen(
        state = viewModel.state,
        onEvent = viewModel::onEvent
    )
}

/**
 * Screen은 State 객체와 onEvent 함수를 노출함.
 * onEvent 함수는 사용자가 수행하는 다양한 액션들을 수신하는 역할.
 */
@Composable
fun LoginScreen(
    **state: LoginState,
    onEvent: (LoginEvent) -> Unit**
) {
    Column {
        if (state.isLoading) {
            CircularProgressIndicator()
        }
        Button(onClick = { onEvent(LoginEvent.Login) }) {
            Text(text = "Login")
        }
        // ...
    }
}