为什么 Jetpack compose 会触发异常重组?

问题描述 投票:0回答:1

我正在做一个项目,遇到了一个问题。这是下面代码中我的问题的最小示例,当文本更改时,TextField 应该仅重新组合。但它重构了整个可组合函数。为什么以及如何处理?

@Composable
fun RecompositionPractice() {
    var text by remember {
        mutableStateOf("")
    }

    Box { 
        TextField(value = text, onValueChange = { text = it })
    }
}

这是我面临同样问题的另一个代码示例。在下面的代码中,

TextField
也应该重组,但
CustomField
也在重组。

    @Composable
    fun MainScreenContent() {
        var userName by remember {
            mutableStateOf("")
        }
        
        CustomField(value = userName, onValueChange = { userName = it })
        
    }
    
    
    @Composable
    fun CustomField(
        value: String,
        onValueChange: (String) -> Unit
    ) {
        TextField(
            label = { Text(text = "Enter Your Name") },
            value = value, 
            onValueChange = { onValueChange(it) }
        )
    }

请提供两个代码示例的解决方案。

android-jetpack-compose android-jetpack
1个回答
0
投票

我想说你的代码完全没问题,你只需要理解为什么它是这样的。

每次在其内部读取的可变状态发生更改时,Composable 都会重新组合,这也会导致子级的重新组合(但不使用更改后的可变状态的子级的重新组合将被跳过)。例如,如果我们稍微包装一下您的代码:

@Composable
fun MainContent1() {
    MainContent2()
}

@Composable
fun MainContent2() {
    var userName by remember {
        mutableStateOf("")
    }

    MainScreenContent3(userName, onValueChange = { userName = it })
}

@Composable
fun MainScreenContent3(
    value: String,
    onValueChange: (String) -> Unit
) {
    CustomField(value = value, onValueChange = onValueChange)
}

MainContent1 不会被重组,但是 MainContent2 和 MainContent3 以及 CustomField(MainContent2 的子级)将被重组,因为 MainContent2 读取已更改的可变状态。 减少组合的方法是将用户名移至可组合项中更深的位置,因此如果代码如下所示:

@Composable
fun MainContent1() {
    MainContent2()
}

@Composable
fun MainContent2() {
    MainScreenContent3()
}

@Composable
fun MainScreenContent3(
) {
    var userName by remember {
        mutableStateOf("")
    }

    CustomField(value = userName, onValueChange = { userName = it })
}

现在 MainContent1 和 MainContent2 不会被重构,但 MainContent3 会被重构。完成同样事情的其他选择是传递 MutableState,但请注意,这并不是真正的最佳解决方案:

@Composable
fun MainContent1() {
    MainContent2()
}

@Composable
fun MainContent2() {
    val userName = remember { mutableStateOf("") }

    MainScreenContent3(userName)
}

@Composable
fun MainScreenContent3(
    value: MutableState<String>
) {
    CustomField(value = value.value, onValueChange = { value.value = it })
}

但是您应该检查是否有两个这样的文本字段:

@Composable
fun MainScreenContent() {
    var userName by remember {
        mutableStateOf("")
    }
    var userName2 by remember {
        mutableStateOf("")
    }
    Column {

        CustomField(value = userName, onValueChange = { userName = it })
        CustomField(value = userName2) { userName2 = it }
    }

}

在一个字段中输入一些内容,您会期望跳过其他字段的重组,情况应该是这样,并且它应该看起来像这样。可以看到MainContent被重构了,还有一个CustomField,但是其他字段的重构被跳过了。

希望这对您有帮助,并且您现在就知道重组会发生什么。

© www.soinside.com 2019 - 2024. All rights reserved.