JetPack Compose 中的副作用
Side-effects in JetPack Compose
虽然我理解或认为我理解,但在 jet-pack compose 中有哪些副作用。
It's any work done in composable which escapes the scope of the composable function
我理解做 I/O 操作或在函数范围外改变变量,提供引用而不清除它(内存泄漏),或改变不可组合状态的局部变量 - 这些都是副作用,因为它们可能会由于重组而导致意外行为和泄漏,这不是确定性的并且可以 运行 多次。为了处理副作用,我们有效果处理程序。
考虑到以上所有内容,我需要在一些情况下弄清楚一点
- 副作用 - 如果是变异对象,它是否适用于除组合对象以外的任何对象?在组合状态(mutableStateOf 等)中不会导致副作用吗?为什么?
- 为什么 callbacks/state/event 提升到你的 activity/fragment/viewmodel,不会导致副作用?
例如
@Composable
fun MyComposable(
viewModel:MyViewModel,
launchSomeActivity:()->Unit
){
var state by remember { mutableStateOf("") }
state = "some string" // not a side-effect?
viewModel.someStringObject = "a" // it's a side-effect?
launchSomeActivity() // it's a side-effect?
when(val screenState = viewModel.screenState.collectAsState().value){
is ScreenState.Success -> launchSomeActivity() // not a side-effect. why?
is ScreenState.Error -> state="some String" // not a side-effect. why?
}
}
我还记得在某处读过,触发回调的副作用,例如 onClick
因为它总是在 UI 线程上执行,或者说从 ViewModel 调用一些 lambda。
是否也想了解上述场景,以及它如何防止副作用、调用 lambda 或回调?
SideEffect
并不意味着其他任何东西都不是 side-effect。这是一个 escape-hatch 应该考虑的事情和组成的影响,但没有或不能在节点树中表达。
例如,Dialog
使用 SideEffect
传达对话框属性,layout-direction 和从 Dialog
参数到创建的 Android 对话框的关闭回调作为组成的结果。这给人一种错觉,即 Dialog
本身就是 Compose 的一部分,即使它使用视图系统来创建对话框。
一般来说,组合函数应该只读取状态,而不是修改状态。如果它确实修改了状态,那么它应该只修改在组合期间创建的状态,并由创建状态的可组合函数直接调用的可组合函数使用;并且仅在任何 children 读取状态之前,而不是在
之后
Side-effect - in case of mutating object, does it holds true for any object other than compose object? As in compose states (mutableStateOf etc..) doesn't lead to side-effects? Why?
可组合函数应该只读取这些 objects 中的状态;它不应该修改这个状态。对于可观察状态,例如 mutableStateOf
,Compose 会观察此状态的变化,并将安排读取状态的可组合函数的重组。您可以使用 mutableStateOf
来执行 side-effects;你不应该。
Why callbacks/state/event hoisting to your activity/fragment/viewmodel,does not lead to side-effect?
如果使用正确,不会,不会;不是从 Compose 的角度来看。组合函数是从它们读取的数据到用户界面树的转换函数。随着视图模型的更改,转换会逐渐 re-evaluated 以产生视图模型的新状态所暗示的 UI。状态提升允许应用程序的 higher-level 部分在数据应如何存储方面具有更多上下文 and/or 验证,以控制 lower-level 应用程序的更通用部分的状态。已提升状态的组件不应该写入状态。如果他们需要改变状态,他们应该使用新的期望状态或对要进行的更改的描述(例如 DeleteCustomer #1234
)调用事件处理程序。实际更改提升状态应该取决于提供的事件处理程序。
state = "some string" // not a side-effect?
不,不是。它初始化 state
因为状态没有逃脱组合被认为是组合的一部分。这不是推荐的做法,但它不是 side-effect.
launchSomeActivity()
这是一个 side-effect,应该在 LaunchEffect
中执行,这将在一个范围内启动 co-routine,当不再在组成.
is ScreenState.Success -> launchSomeActivity() // not a side-effect. why?
这是一个副作用,原因相同,答案相同。
is ScreenState.Error -> state="some String" // not a side-effect. why?
这不是上面提到的 side-effect(即 side-effect 意味着它对构图之外的东西有影响,但事实并非如此),但是,如果 state
已经被读过,那么它被认为是向后写,并且非常不鼓励,因为它可能导致重复组合,也许是无限期地重复;因为任何已经阅读过的内容都可能会重新安排再次执行。
虽然我理解或认为我理解,但在 jet-pack compose 中有哪些副作用。
It's any work done in composable which escapes the scope of the composable function
我理解做 I/O 操作或在函数范围外改变变量,提供引用而不清除它(内存泄漏),或改变不可组合状态的局部变量 - 这些都是副作用,因为它们可能会由于重组而导致意外行为和泄漏,这不是确定性的并且可以 运行 多次。为了处理副作用,我们有效果处理程序。
考虑到以上所有内容,我需要在一些情况下弄清楚一点
- 副作用 - 如果是变异对象,它是否适用于除组合对象以外的任何对象?在组合状态(mutableStateOf 等)中不会导致副作用吗?为什么?
- 为什么 callbacks/state/event 提升到你的 activity/fragment/viewmodel,不会导致副作用?
例如
@Composable
fun MyComposable(
viewModel:MyViewModel,
launchSomeActivity:()->Unit
){
var state by remember { mutableStateOf("") }
state = "some string" // not a side-effect?
viewModel.someStringObject = "a" // it's a side-effect?
launchSomeActivity() // it's a side-effect?
when(val screenState = viewModel.screenState.collectAsState().value){
is ScreenState.Success -> launchSomeActivity() // not a side-effect. why?
is ScreenState.Error -> state="some String" // not a side-effect. why?
}
}
我还记得在某处读过,触发回调的副作用,例如 onClick
因为它总是在 UI 线程上执行,或者说从 ViewModel 调用一些 lambda。
是否也想了解上述场景,以及它如何防止副作用、调用 lambda 或回调?
SideEffect
并不意味着其他任何东西都不是 side-effect。这是一个 escape-hatch 应该考虑的事情和组成的影响,但没有或不能在节点树中表达。
例如,Dialog
使用 SideEffect
传达对话框属性,layout-direction 和从 Dialog
参数到创建的 Android 对话框的关闭回调作为组成的结果。这给人一种错觉,即 Dialog
本身就是 Compose 的一部分,即使它使用视图系统来创建对话框。
一般来说,组合函数应该只读取状态,而不是修改状态。如果它确实修改了状态,那么它应该只修改在组合期间创建的状态,并由创建状态的可组合函数直接调用的可组合函数使用;并且仅在任何 children 读取状态之前,而不是在
之后Side-effect - in case of mutating object, does it holds true for any object other than compose object? As in compose states (mutableStateOf etc..) doesn't lead to side-effects? Why?
可组合函数应该只读取这些 objects 中的状态;它不应该修改这个状态。对于可观察状态,例如 mutableStateOf
,Compose 会观察此状态的变化,并将安排读取状态的可组合函数的重组。您可以使用 mutableStateOf
来执行 side-effects;你不应该。
Why callbacks/state/event hoisting to your activity/fragment/viewmodel,does not lead to side-effect?
如果使用正确,不会,不会;不是从 Compose 的角度来看。组合函数是从它们读取的数据到用户界面树的转换函数。随着视图模型的更改,转换会逐渐 re-evaluated 以产生视图模型的新状态所暗示的 UI。状态提升允许应用程序的 higher-level 部分在数据应如何存储方面具有更多上下文 and/or 验证,以控制 lower-level 应用程序的更通用部分的状态。已提升状态的组件不应该写入状态。如果他们需要改变状态,他们应该使用新的期望状态或对要进行的更改的描述(例如 DeleteCustomer #1234
)调用事件处理程序。实际更改提升状态应该取决于提供的事件处理程序。
state = "some string" // not a side-effect?
不,不是。它初始化 state
因为状态没有逃脱组合被认为是组合的一部分。这不是推荐的做法,但它不是 side-effect.
launchSomeActivity()
这是一个 side-effect,应该在 LaunchEffect
中执行,这将在一个范围内启动 co-routine,当不再在组成.
is ScreenState.Success -> launchSomeActivity() // not a side-effect. why?
这是一个副作用,原因相同,答案相同。
is ScreenState.Error -> state="some String" // not a side-effect. why?
这不是上面提到的 side-effect(即 side-effect 意味着它对构图之外的东西有影响,但事实并非如此),但是,如果 state
已经被读过,那么它被认为是向后写,并且非常不鼓励,因为它可能导致重复组合,也许是无限期地重复;因为任何已经阅读过的内容都可能会重新安排再次执行。