2

我有一个TextField用于搜索查询和一个Button将执行搜索,结果显示在列中。由于搜索需要几秒钟才能运行,我希望它在按钮按下而不是文本更改时执行。

这是一个简化的演示:

Column {
    val list = remember { mutableStateListOf<String>() }
    val textFieldValue = remember { mutableStateOf(TextFieldValue("")) }

    TextField(
        value = textFieldValue.value,
        onValueChange = { textFieldValue.value = it }
    )

    Button({
        list.clear()
        list.addAll(textFieldValue.value.text.split(""))
    }) {
        Text("Search")
    }

    list.forEach {
        println("test")
        Text(it)
    }
}

第一次按下按钮后,foreach 循环将在文本更改时运行。即使单击TextField也会重新运行循环。这不会对文本更改运行搜索,但会重新呈现结果,这会导致在文本字段中键入时出现故障。

如何防止这种情况?

4

3 回答 3

5

以上对于 Jetpack Compose 来说是正确的。作者想了解 Compose Desktop,但那里的情况还不一样,因为它还处于 alpha 阶段,还没有进行太多优化。

修改一个remember值总是会导致所有视图的重组,它的读取值。

Any changes to value will schedule recomposition of any composable functions that read value. 文件

阻止它的方法是将所有读取remember值的视图移到单独的视图中。每次值更改都会重新组合remember,但不会影响容器。

在您的情况下,这很简单:只需移动TextField并传递textFieldValue给新函数。您可以转发您需要的所有参数,例如modifier,textStyle等。

@Composable
fun TestView(
) {
    Column {
        val textFieldValue = remember { mutableStateOf(TextFieldValue("")) }
        val list = remember { mutableStateListOf<String>("test") }

        TextField(textFieldValue)

        Button({
            list.clear()
            list.addAll(textFieldValue.value.text.split(""))
        }) {
            Text("Search")
        }

        list.forEach {
            println("test $it")
            Text(it)
        }
    }
}

@Composable
fun TextField(
    textFieldValue: MutableState<TextFieldValue>,
) {
    TextField(
        value = textFieldValue.value,
        onValueChange = { textFieldValue.value = it }
    )
}

我不确定为什么没有具有这种语义的系统函数,但在撰写时他们更喜欢状态提升模式来匹配 UDF。

于 2021-08-04T02:44:31.597 回答
0
Column {
    val list = remember { mutableStateListOf<String>() }
    var textFieldValue = remember { mutableStateOf(TextFieldValue("")) }
    var searchTerm = remember { textFieldValue.value.text.copy() }

    TextField(
        value = textFieldValue.value,
        onValueChange = { textFieldValue.value = it }
    )

    Button({
        searchTerm = textFieldValue.value.text.copy()
        list.clear()
        list.addAll(searchTerm.text.split(""))
    }) {
        Text("Search")
    }

    list.forEach {
        println("test")
        Text(it)
    }
}

试试这个

于 2021-08-03T20:49:42.920 回答
0

我不喜欢MutableState<> 作为参数四处走动,就像我从不LiveData<>用作参数一样。相反,您可以将阅读转换为 lambda:

@Composable
fun TextField(value: ()->TextFieldValue, 
              onValueChange(TextFieldValue)->Unit) {
    TextField(
        value = value(),
        onValueChange = { onValueChange(it) }
    )
} 
// call like
TextField(
        value = { textFieldValue.value },
        onValueChange = { textFieldValue.value = it }
)
于 2021-09-12T14:12:22.177 回答