1

我想从传递给我的 Composable 的参数初始化一个remembered 。初始化后,我想修改这个列表并记住重组时的变化(因此是)。问题是这是从 Room 数据库异步加载的,并且在第一次合成时,它是空的。永远不会被值填充,所以我假设在重组时初始化块不会再次执行。StateMapListrememberListexpandedStates Map

如何正确初始化此 StateMap?

@Composable
fun TodoList(
    todos: List<Todo>,
    [...]
) {
    // this map stays empty
    val expandedStates = remember {
        mutableStateMapOf<Long, Boolean>().apply {
            todos.map { todo ->
                todo.id to false
            }.toMap().also {
                putAll(it)
            }
        }
    }

    [...]
}
4

2 回答 2

1

关于 map 中不存在键的问题,正如您所说。因此,您需要告诉记住,待办事项是需要更新的键。如果你不想失去一部分的状态,记住你可以打开第二个。

在下面的代码中,我首先创建了地图并在周围放置了一个记忆以保持状态。其次,我创建了一个每次刷新 todos 时都会刷新的记忆。在那里,我合并了两个映射并将现有值或 false 关联为默认值。

/* Jetpack Compose Desktop but still applies to Android */

data class TODOItem(val id: Long, val content: String)

@ExperimentalAnimationApi
@ExperimentalMaterialApi
@Composable
fun TODOList(todos: List<TODOItem>) {
    val expandedStates = remember { mutableStateMapOf<Long, Boolean>() }
    remember(todos) {
        if (expandedStates.isNotEmpty()) {
            val updated = todos.map { todo -> todo.id }
            val mergeMap = (expandedStates.keys + updated).associateWith{ expandedStates[it] ?: false }
            expandedStates.clear()
            expandedStates.putAll(mergeMap)
        } else {
            expandedStates.putAll(todos.associate { todo -> todo.id to false })
        }
    }
    LazyColumn {
        items(todos) { todo ->
            Card(
                onClick = {
                    expandedStates[todo.id] = expandedStates[todo.id]?.not() ?: true
                }
            ) {
                Column {
                    Text(text = "id ${todo.id}")
                    AnimatedVisibility(
                        visible = expandedStates[todo.id]!!
                    ) {
                        Text(text = "content ${todo.content}")
                    }
                }
            }
        }
    }
}

@ExperimentalMaterialApi
@ExperimentalAnimationApi
fun main() {
    Window {
        val todos = remember { mutableStateOf(emptyList<TODOItem>()) }
        var items = 0
        LaunchedEffect(Unit) {
            fixedRateTimer(period = 2000L) {
                todos.value = if (todos.value.isEmpty()) {
                    items += 20
                    List(items) { TODOItem(it.toLong(), "content $it") }
                } else emptyList()
            }
        }
        TODOList(
            todos = todos.value
        )
    }
}

注意:如果您有一个删除数据库中项目的查询,则 ID 仍然存在于 UI 中。

如果您的问题只需要您在一个空列表后更新一次,您可以从您的代码中传递记住一个键来更新。

val expandedStates = remember(todos) {
    mutableStateMapOf(*todos.map { todo -> todo.id to false }.toTypedArray())
}
于 2021-07-30T14:31:42.377 回答
-1

只需删除要记住的电话即可。另外,我假设传入的参数todos也是一个状态持有者,它将触发重组。阅读有关记住的文档以了解更多信息。

谢谢!

于 2021-07-30T08:58:04.063 回答