我在 Jetpack Compose 中有一个嵌套的组件结构,其中深层嵌套的组件需要与 ViewModel 交互。我正在尝试确定处理此交互的最佳方法。
这是我的组件结构:
class MainViewModel : ViewModel() {
fun handleButtonClick() {
// Do something
}
}
// Approach 1: Passing ViewModel down
@Composable
fun ComposableA(viewModel: MainViewModel) {
ComposableB()
ComposableC(viewModel = viewModel)
}
@Composable
fun ComposableC(viewModel: MainViewModel) {
ComposableD(viewModel = viewModel)
}
@Composable
fun ComposableD(viewModel: MainViewModel) {
Button(onClick = { viewModel.handleButtonClick() }) {
Text("Click Me")
}
}
// Approach 2: Using Callbacks
@Composable
fun ComposableA(viewModel: MainViewModel) {
val onButtonClick = { viewModel.handleButtonClick() }
ComposableB()
ComposableC(onButtonClick = onButtonClick)
}
@Composable
fun ComposableC(onButtonClick: () -> Unit) {
ComposableD(onButtonClick = onButtonClick)
}
@Composable
fun ComposableD(onButtonClick: () -> Unit) {
Button(onClick = onButtonClick) {
Text("Click Me")
}
}
Which approach is considered better practice?
传递
ViewModel
给 Composables 使它们依赖于该 ViewModel,这使得预览或测试 Composable 变得困难,尤其是在 ViewModel 中注入参数的情况下。如果 ViewModel 具有与存储库、存储库或 savedStateHandle 相关的用例,则要运行预览,您将需要做大量工作才能运行 Composable。
稳定性不是主要问题
ViewModel
,因为您可以使用@Stable
来ViewModel
通知编译器您的 ViewModel 是稳定的,或者您可以启用强跳过,这equals
也适用于不稳定的参数。默认情况下,不稳定参数使用引用相等性 (===) 来确定该参数是否已更改,如果它们所在的范围或 Composable 的父级中存在组合,但使用强跳过,如果新值等于前一个值,则不会安排重组。另外,如果
ViewModel.handleClick
不稳定,使用下面的方法将无法防止不必要的重组。您可以查看此答案的lambda-stability部分。您应该使用记住 lambda
或者启用 strong-skipping,默认情况下使用记忆包装 lambda。
不要将视图模型传递给可组合项。
您希望尽可能减少重组。为了让 Compose 能够跳过函数,它必须确定参数是否已更改。幕后有很多优化,但作为开发人员,您可以轻松实现:仅传递不可变和稳定的参数。视图模型既不是,也不是,因此您不应将它们作为参数传递。
相反,应该这样做:
MainScreen
需要给定视图模型的最顶层可组合项在哪里。