JetPack Compose 中的副作用
虽然我理解或认为我理解,喷气背包有哪些副作用。
It's any work done in composable which escapes the scope of the composable function
我理解做诸如 I/O 操作或在函数作用域之外改变变量、提供引用而不清除它(内存泄漏)或改变不可组合状态的局部变量之类的事情 - 这些都是副作用,因为它们可以由于重组而导致意外行为和泄漏,重组是不确定的并且可以运行多次。为了解决副作用,我们有效果处理程序。
考虑到上述所有内容,我需要在一些场景中澄清一些
- 副作用 - 在变异对象的情况下,它是否适用于除组合对象之外的任何对象?正如在组合状态(mutableStateOf 等..)中不会导致副作用?为什么?
- 为什么回调/状态/事件提升到您的活动/片段/视图模型不会导致副作用?
例如
@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 或回调?
While I understand or think I understand, what side-effects are in jet-pack compose.
It's any work done in composable which escapes the scope of the composable function
I understand doing stuff like I/O operations or mutating a variable outside of function scope, giving reference and not clearing it (memory leak), or mutating a local variable that is not composable state - these all are side-effects, as they can lead to unexpected behavior and leaks because of recomposition, which is not deterministic and can run many times. And to take care of side-effects, we have effect-handlers.
Considering everything above, I need a bit of clarity in a few scenarios
- 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?
- Why callbacks/state/event hoisting to your activity/fragment/viewmodel,does not lead to side-effect?
For example
@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?
}
}
I also recall reading somewhere, trigger side-effects from callbacks, such as onClick
as that always executes on UI thread, or say calling some lambda from ViewModel.
Would like to understand the above scenario as well, as in how it prevents side-effects, calling a lambda or a callback?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
SideEffect
并不意味着其他任何东西都不是副作用。它是一个逃生舱口,用于应对应该考虑的事物和组合的效果,但没有或不能在节点树中表达。例如,
Dialog
使用SideEffect
将对话框属性、布局方向和关闭回调从Dialog
参数传递到作为 Android 对话框创建的组合的结果。这会产生一种错觉,即Dialog
本身就是 Compose 的一部分,尽管它使用视图系统来创建对话框。一般来说,组合函数应该只读取状态,而不应该修改状态。如果它确实修改状态,则应该仅修改在组合期间创建的状态,并由创建状态的可组合函数直接调用的可组合函数使用;并且仅在任何孩子阅读该状态之前,而不是之后。
可组合函数应该只读取这些对象中的状态;它不应该修改这个状态。对于可观察状态,例如
mutableStateOf
,Compose 会观察此状态的更改,并安排读取该状态的可组合函数的重组。您可以使用 mutableStateOf 来执行副作用;你不应该。如果使用得当,不会;不是从 Compose 的角度来看。组合函数是从读取的数据到用户界面树的转换函数。随着视图模型的更改,转换会逐渐重新评估,以生成视图模型的新状态所隐含的 UI。状态提升允许应用程序的较高级别部分对如何存储和/或验证数据有更多上下文,以控制应用程序的较低级别、更通用部分的状态。具有提升状态的组件永远不应该写入该状态。如果他们需要更改状态,则应使用新的所需状态或要进行的更改的描述来调用事件处理程序(例如
DeleteCustomer #1234
)。应该由提供的事件处理程序来实际更改提升状态。不,不是。它初始化
state
,因为状态不会转义组合被视为组合的一部分。这不是推荐的做法,但它不是副作用。这是一个副作用,应该在
LaunchEffect
中执行,它将在一个范围内启动协同例程,当组合函数不存在时,该协同例程将自动取消不再在作文中调用。这是出于相同原因和相同答案的副作用。
这不是上面提到的副作用(即副作用意味着它对组合之外的东西有影响,但事实并非如此),但是,如果
state
已经被阅读过,那么它被认为是向后写入并且强烈不鼓励,因为它可能导致组合被重复,也许无限期地重复;因为任何已经读取的内容都可能会被重新安排再次执行。The
SideEffect
doesn't imply that anything else isn't a side-effect. It is an escape-hatch for things should be considered and effect of composition but are not, or cannot be, expressed in the node tree.For example,
Dialog
usesSideEffect
to communicated dialog properties, layout-direction and the dismiss callback from theDialog
parameters to the Android dialog created as a result of composition. This presents the illusion thatDialog
is natively part of Compose even though it uses the view system to create the dialog.In general, a composition function should only read state, not modify state. If it does modify state it should be only to state created during composition and used by the composable functions called directly by the composable function that created the state; and only before any of the children read the state, and not after.
Composable functions should only read the state in these objects; it should not be modifying this state. For observable state, such as
mutableStateOf
, Compose observes changes to this state and will schedule a recomposition of the composable functions that read the state. You can usemutableStateOf
to perform side-effects; you shouldn't.Not if they are used correctly, no; not from Compose's perspective. Composition functions are a transform function from the data they read to user interface tree. As the view model changes, the transform is incrementally re-evaluated to produce the UI implied by the new state of the view model. State hoisting allows higher-level parts of the application that have more context over how the data should be stored and/or validated, to control the state of lower-level, more generic parts of the application. The components that have hoisted state should never write to the state. If they need to state to be changed they should call an event handler with the new desired state or with a description of what change to make (e.g.
DeleteCustomer #1234
). It should be up to the provided event handlers to actually make the change to the hoisted state.No, it is not. It initializes
state
as state does not escape the composition is considered part of the composition. This is not recommended practice but it is not a side-effect.This is a side-effect and should be performed in
LaunchEffect
which will launch the co-routine in a scope that will automatically be cancelled when the composition function is no longer called in the composition.This is a side effect for the same reason with the same answer.
This is not a side-effect as mentioned above (i.e. a side-effect implies it has an effect to something outside of composition, this doesn't), but, if
state
has already been read then it is considered a backwards write and heavily discouraged as it could cause composition to be repeated, perhaps indefinitely; as anything that has already read it might be rescheduled to be executed again.