What is the preferred way of instantiating a viewModel for a screen composable?
Option 1: inside the composable
eg 1.
@Composable
fun LoginScreen(
navController: NavController,
modifier: Modifier = Modifier,
loginViewModel: LoginViewModel = koinViewModel<LoginViewModel>()
){
}
eg 2.
@Composable
fun LoginScreen(
navController: NavController,
modifier: Modifier = Modifier,
) {
val loginViewModel = koinViewModel<LoginViewModel>()
}
I note that with this approach, it becomes impossible to show a preview of the screen on Android Studio, unless you create another composable that doesn't care about a viewModel and call it here. I don't want to do that.
Option 2: inside the navgraph, then pass an action lambda and state object
on the navigation graph:
composable(route = Screen.LoginScreen.route) {
val loginViewModel = koinViewModel<LoginViewModel>()
val state by loginViewModel.loginState.collectAsStateWithLifecycle()
LoginScreen(
navController = navController,
state = state,
onAction = { loginAction ->
loginViewModel.onAction(loginAction)
}
)
}
on the composable:
@Composable
fun LoginScreen(
navController: NavController,
modifier: Modifier = Modifier,
state: LoginState,
onAction: (LoginAction) -> Unit
){
}
With this approach, I am able to preview my LoginScreen composable. This however means I need to use actions for all possible UI actions, and pass my state as well. I don't mind this.
Now I am not sure according to best practices, which of these two would be the best approach? Could there be another recommended approach? Any pointers?
Please have a look at the Previews in ViewModels chapter in the official documentation:
When you try to preview a composable with
ViewModel
, Android Studio shows an error when rendering the particular composable.
If you want to preview a composable that uses a
ViewModel
, you should create another composable with the parameters fromViewModel
passed as arguments of the composable. This way, you don't need to preview the composable that uses the ViewModel.
We can conclude from the documentation that
Also check out this stackoverflow question which also recommends following approach 2 by lifting the ViewModel to the parent Composable.