JetpackComposeとViewModelの運用
- JetpackComposeでのViewModelの運用方法に疑問を抱いたので、軽く調べたメモ用とする。
サンプルコードを見て学ぶ
以下サンプルコード↓
class HelloViewModel : ViewModel() {
private val _name = MutableLiveData("")
val name: LiveData<String> = _name
fun onNameChange(newName: String) {
_name.value = newName
}
}
// 画面単位といった大きな粒度でViewModelと結合する
@Composable
fun HelloScreen(helloViewModel: HelloViewModel = viewModel()) {
val name: String by helloViewModel.name.observeAsState("")
HelloContent(name = name, onNameChange = { helloViewModel.onNameChange(it) })
}
// 子Composableには純粋なパラメータとコールバックでやりとりをする
@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "Hello, $name",
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5
)
OutlinedTextField(
value = name,
onValueChange = onNameChange,
label = { Text("Name") }
)
}
}
注意点は以下の二つ
1, ViewModel自体を子Composableに渡さない
コンポーザブルは、必要なものにのみ渡す ことが重要です。
これにより子Composableの依存関係が明確になり、また再利用性、テスト容易性が高まります。以下のようなコードにしないこと。
@Composable
fun HelloContent(helloViewModel: HelloViewModel) {
/* ... */
}
2, ViewModelをCompositionLocalで配布しない
CompositionLocalは子Composableに暗黙的にデータを伝えることが出来ます。
これにより、バケツリレーが解消される一方、データが追いにくくなるというデメリットもあります。
公式によるCompositionLocal を使用すべきかどうかの判断 によると、本来ViewModelを必要としていない子ComposableからもViewModelのインスタンスが参照できてしまうことに触れ、CompositionLocalでViewModelを保持すべきでないと明言されています。
上記をまとめると、Jetpack ComposeとViewModelは疎であるべきであり、大部分でViewModelを意識しない形にすることが理想でしょう。