撰写:remember() with keys vs. derivedStateOf()
Compose: remember() with keys vs. derivedStateOf()
这两种方法有什么区别?
val result = remember(key1, key2) { computeIt(key1, key2) }
(Docs)
val result by remember { derivedStateOf { computeIt(key1, key2) } }
(Docs)
如果key1
和key2
都没有改变,避免重新计算
.
如果下游状态是派生的,第二个也避免了重新计算,但除此之外,它们的行为是相同的,不是吗?
据我所知,这里没有区别。这只是一个巧合,两个构造在这里在这种情况下做同样的事情。但是,还是有区别的!
最大的一个是 derivedStateOf
不可组合,并且它自己不进行缓存(remember
可以)。因此 derivedStateOf
用于长 运行ning 计算,只有在键更改时才必须 运行。或者它可以用于合并不可组合的多个状态(例如在自定义 class 中)。
我认为对于“局外人”来说,确切的解释是模糊的,我们需要一些撰写团队成员的意见:)。我以上的来源是 this one thread on slack 和我自己的实验
编辑:
今天我学习了另一种derivedStateOf
用法,非常重要。当使用一些非常频繁使用的值进行计算时,它可以用来限制重组计数。
示例:
// we have a variable scrollState: Int that gets updated every time user scrolls
// we want to update our counter for every 100 pixels scrolled.
// To avoid recomposition every single pixel change we are using derivedStateOf
val counter = remember {
derivedStateOf {
(scrollState / 100).roundToInt()
}
}
// this will be recomposed only on counter change, so it will "ignore" scrollState in 99% of cases
Text(counter.toString()).
我的来源尽可能直接——来自 compose 运行time 和快照系统的作者,Chuck Jazdzewski 本人。我强烈推荐在这里和他一起看直播:https://www.youtube.com/watch?v=waJ_dklg6fU
编辑 2:
我们终于有了一些官方性能文档,其中很少提到 derivedStateOf
。所以 derivedStateOf
的官方目的是限制组合数(就像在我的例子中一样)。 sauce
val result = remember(key1, key2) { computeIt(key1, key2) }
re-calculates when key1
or key2
changes but derivedStateOf
is for tracking a change in a or more State/MutableState as stated在文档中为
var a by remember { mutableStateOf(0) }
var b by remember { mutableStateOf(0) }
val sum = remember { derivedStateOf { a + b } }
// Changing either a or b will cause CountDisplay to recompose but not trigger Example
// to recompose.
CountDisplay(sum)
当您需要跟踪 State 对象 属性 的变化时,使用 derivedStateOf 会很方便。您存储在 State 中的值可以是一个对象,但是当您需要跟踪对象的一个或某些属性时,您需要使用 derivedStateOf。如果它不是从 State/MutableState
或具有带有 @Stable
注释的接口的对象派生的,则 Composable 将不会重组,因为重组需要状态更改。
例如,您需要在某个阈值或状态后触发另一个重组的输入布局或项目数。
var numberOfItems by remember {
mutableStateOf(0)
}
// Use derivedStateOf when a certain state is calculated or derived from other state objects.
// Using this function guarantees that the calculation will only occur whenever one
// of the states used in the calculation changes.
val derivedStateMax by remember {
derivedStateOf {
numberOfItems > 5
}
}
Column(modifier = Modifier.padding(horizontal = 8.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(text = "Amount to buy: $numberOfItems", modifier = Modifier.weight(1f))
IconButton(onClick = { numberOfItems++ }) {
Icon(imageVector = Icons.Default.Add, contentDescription = "add")
}
Spacer(modifier = Modifier.width(4.dp))
IconButton(onClick = { if (derivedStateMin) numberOfItems-- }) {
Icon(imageVector = Icons.Default.Remove, contentDescription = "remove")
}
}
if (derivedStateMax) {
Text("You cannot buy more than 5 items", color = Color(0xffE53935))
}
}
这是 whatsapp 文本输入,通过读取文本根据文本是否为空显示图标
internal fun ChatInput(modifier: Modifier = Modifier, onMessageChange: (String) -> Unit) {
var input by remember { mutableStateOf(TextFieldValue("")) }
val textEmpty: Boolean by derivedStateOf { input.text.isEmpty() }
Row(
modifier = modifier
.padding(horizontal = 8.dp, vertical = 6.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.Bottom
) {
ChatTextField(
modifier = modifier.weight(1f),
input = input,
empty = textEmpty,
onValueChange = {
input = it
}
)
Spacer(modifier = Modifier.width(6.dp))
FloatingActionButton(
modifier = Modifier.size(48.dp),
backgroundColor = Color(0xff00897B),
onClick = {
if (!textEmpty) {
onMessageChange(input.text)
input = TextFieldValue("")
}
}
) {
Icon(
tint = Color.White,
imageVector = if (textEmpty) Icons.Filled.Mic else Icons.Filled.Send,
contentDescription = null
)
}
}
}
这两种方法有什么区别?
val result = remember(key1, key2) { computeIt(key1, key2) }
(Docs)val result by remember { derivedStateOf { computeIt(key1, key2) } }
(Docs)
如果key1
和key2
都没有改变,避免重新计算
.
如果下游状态是派生的,第二个也避免了重新计算,但除此之外,它们的行为是相同的,不是吗?
据我所知,这里没有区别。这只是一个巧合,两个构造在这里在这种情况下做同样的事情。但是,还是有区别的!
最大的一个是 derivedStateOf
不可组合,并且它自己不进行缓存(remember
可以)。因此 derivedStateOf
用于长 运行ning 计算,只有在键更改时才必须 运行。或者它可以用于合并不可组合的多个状态(例如在自定义 class 中)。
我认为对于“局外人”来说,确切的解释是模糊的,我们需要一些撰写团队成员的意见:)。我以上的来源是 this one thread on slack 和我自己的实验
编辑:
今天我学习了另一种derivedStateOf
用法,非常重要。当使用一些非常频繁使用的值进行计算时,它可以用来限制重组计数。
示例:
// we have a variable scrollState: Int that gets updated every time user scrolls
// we want to update our counter for every 100 pixels scrolled.
// To avoid recomposition every single pixel change we are using derivedStateOf
val counter = remember {
derivedStateOf {
(scrollState / 100).roundToInt()
}
}
// this will be recomposed only on counter change, so it will "ignore" scrollState in 99% of cases
Text(counter.toString()).
我的来源尽可能直接——来自 compose 运行time 和快照系统的作者,Chuck Jazdzewski 本人。我强烈推荐在这里和他一起看直播:https://www.youtube.com/watch?v=waJ_dklg6fU
编辑 2:
我们终于有了一些官方性能文档,其中很少提到 derivedStateOf
。所以 derivedStateOf
的官方目的是限制组合数(就像在我的例子中一样)。 sauce
val result = remember(key1, key2) { computeIt(key1, key2) }
re-calculates when key1
or key2
changes but derivedStateOf
is for tracking a change in a or more State/MutableState as stated在文档中为
var a by remember { mutableStateOf(0) }
var b by remember { mutableStateOf(0) }
val sum = remember { derivedStateOf { a + b } }
// Changing either a or b will cause CountDisplay to recompose but not trigger Example
// to recompose.
CountDisplay(sum)
当您需要跟踪 State 对象 属性 的变化时,使用 derivedStateOf 会很方便。您存储在 State 中的值可以是一个对象,但是当您需要跟踪对象的一个或某些属性时,您需要使用 derivedStateOf。如果它不是从 State/MutableState
或具有带有 @Stable
注释的接口的对象派生的,则 Composable 将不会重组,因为重组需要状态更改。
例如,您需要在某个阈值或状态后触发另一个重组的输入布局或项目数。
var numberOfItems by remember {
mutableStateOf(0)
}
// Use derivedStateOf when a certain state is calculated or derived from other state objects.
// Using this function guarantees that the calculation will only occur whenever one
// of the states used in the calculation changes.
val derivedStateMax by remember {
derivedStateOf {
numberOfItems > 5
}
}
Column(modifier = Modifier.padding(horizontal = 8.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(text = "Amount to buy: $numberOfItems", modifier = Modifier.weight(1f))
IconButton(onClick = { numberOfItems++ }) {
Icon(imageVector = Icons.Default.Add, contentDescription = "add")
}
Spacer(modifier = Modifier.width(4.dp))
IconButton(onClick = { if (derivedStateMin) numberOfItems-- }) {
Icon(imageVector = Icons.Default.Remove, contentDescription = "remove")
}
}
if (derivedStateMax) {
Text("You cannot buy more than 5 items", color = Color(0xffE53935))
}
}
这是 whatsapp 文本输入,通过读取文本根据文本是否为空显示图标
internal fun ChatInput(modifier: Modifier = Modifier, onMessageChange: (String) -> Unit) {
var input by remember { mutableStateOf(TextFieldValue("")) }
val textEmpty: Boolean by derivedStateOf { input.text.isEmpty() }
Row(
modifier = modifier
.padding(horizontal = 8.dp, vertical = 6.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.Bottom
) {
ChatTextField(
modifier = modifier.weight(1f),
input = input,
empty = textEmpty,
onValueChange = {
input = it
}
)
Spacer(modifier = Modifier.width(6.dp))
FloatingActionButton(
modifier = Modifier.size(48.dp),
backgroundColor = Color(0xff00897B),
onClick = {
if (!textEmpty) {
onMessageChange(input.text)
input = TextFieldValue("")
}
}
) {
Icon(
tint = Color.White,
imageVector = if (textEmpty) Icons.Filled.Mic else Icons.Filled.Send,
contentDescription = null
)
}
}
}