derivedStateOf
仅适用于State对象.selectedOption
不是一个州,因此它的任何更改都不会被检测到.
让我们更详细地看看这个.在您最初的非工作示例中,只有remember()
,derivedStateOf
在第一次合成时执行.它还执行Lambda并跟踪所有使用的State对象.我们预计情况如下:
heightValue
isOk
selectedOption
那么derivedStateOf
的结果就是remember
ed,因此在重新组合时不会再次执行.没关系:当上述列表中的任何状态发生变化时,现在创建的派生状态会自动更新.
除了它只适用于1.和2.,它对3不起作用.
由于derivedStateOf
只跟踪其Lambda中使用的实际State个对象,因此很明显,它不会在3时更新.更改:selectedOption
只是一个简单的字符串,而不是State.更有趣的问题是为什么它does适用于1.和2.不过,由于它们是also个无州,只有Int和布尔值.但这并不完全正确.它们实际上是您使用by
关键字检索到的委托.这意味着您可以将它们用作简单的Int和布尔值,但每当读取它们的值时,委托对象的getValue
函数实际上就会执行.当设置它们的值时,将改为调用setValue
.Kotlin向您隐藏了所有这些,以便您的代码看起来更干净,但这就是访问委托时实际发生的情况.最后,1.和2.一个州是delegates个,因此derivedStateOf
个州可以看到这些州并监控它们的变化.
然而,selectedOption
是通过解构MutableState创建的.这给您留下了一个简单的字符串,其中包含解构时的值.棘手的是,对于大多数情况下,这就足够了,所以感觉与委托州没有太大不同:
Text(selectedOption)
这将按预期工作,并在每次基础状态selectedOption
更改时更新.这是因为Compose运行时会跟踪所有State读取,而解构State也算作如此.当状态发生变化时,它就会重新组合功能,因此解构被重复并更新selectedOption
.但derivedStateOf
位于remember
之后,不受此类重组的影响.这就是为什么它会跟踪所有State对象本身.但它从来没有看到selectedOption
后面国家的解构,所以它只看到了结果,那是一个简单的字符串,而不是一个国家.
我们现在可以修改上面derivedStateOf
个跟踪的州列表:
heightValue
名代表背后的国家反对
isOk
名代表背后的国家反对
- Not
selectedOption
,因为这只是一个简单的字符串
Lambda中访问的唯一州是1.和2.,所以无论你用3.做什么,它不会影响derivedStateOf
.
当您使用remember(selectedOption)
时,它似乎有效,但实际发生的情况是,每次selectedOption
更改并创建一个新的状态时,整个派生状态就会被丢弃.再次执行Lambda,并创建上述应观察更改的State对象列表,但3并不重要.实际上并不在列表中,因为当它发生变化时,您只需创建一个new派生State对象,就不会让current派生State对象更新.
解决这个问题的正确方法是将国家控制在selectedOption
左右.或者像处理1一样委托它.和2.,或者如果出于某种原因您不想这样做,则可以这样做:
val selectedOptionState = remember { mutableStateOf(radioOptions[0]) }
val (selectedOption, onOptionSelected) = selectedOptionState
val calculatedValue by remember {
derivedStateOf {
calcNewValueInch(
pickerValue = heightValue,
isOk = isOk,
selectedOption = selectedOptionState.value, // this accesses the State now
)
}
}
在这种情况下,我建议您完全删除解构,只访问selectedOptionState.value
,这样代码的读者就不会想知道为什么您有时使用这个,有时使用那个来访问同一个州.