You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何构建Composable以仅触发一次重组并避免重复调用loadJson

解决Composable中重复执行HTTP请求的问题

你现在的代码里,loadJson直接写在Composable的根作用域中,而Composable每次重组(比如textToShow更新触发界面刷新时)都会重新执行整个函数体,这就导致loadJson被反复调用。要解决这个问题,得把异步请求放到副作用作用域里,确保只在特定时机执行。

基础实现:仅加载一次

用LaunchedEffect就可以搞定,它会在Composable首次进入组合时启动协程执行代码,而且只有当指定的key变化时才会重新执行。传Unit作为key,就能保证请求只发一次:

@Composable
fun Schedule() {
    var textToShow by remember { mutableStateOf("loading...") }

    // 仅在Composable首次渲染时执行一次请求
    LaunchedEffect(key1 = Unit) {
        RemoteConfig.loadJson(
            "schedule.api",
            onSuccess = { routes ->
                textToShow = routes[1].jsonObject.toString()
            },
            onError = { e ->
                textToShow = "Failed to load bus schedule. ($e)"
            }
        )
    }

    Text(textToShow)
}

进阶:支持主动刷新

如果需要做下拉刷新这类主动触发重新加载的功能,可以把key换成一个刷新触发器变量,每次刷新时改变这个变量的值,就能让LaunchedEffect重新执行请求:

@Composable
fun Schedule(refreshTrigger: Int = 0) {
    var textToShow by remember { mutableStateOf("loading...") }

    // 当refreshTrigger变化时,重新发起请求
    LaunchedEffect(key1 = refreshTrigger) {
        textToShow = "loading..." // 刷新时重置加载状态
        RemoteConfig.loadJson(
            "schedule.api",
            onSuccess = { routes ->
                textToShow = routes[1].jsonObject.toString()
            },
            onError = { e ->
                textToShow = "Failed to load bus schedule. ($e)"
            }
        )
    }

    // 示例:添加刷新按钮,点击时让父组件更新refreshTrigger(比如+1)
    Button(onClick = { /* 这里触发父组件更新refreshTrigger */ }) {
        Text("Refresh")
    }

    Text(textToShow)
}

额外优化:改用协程替代回调(推荐)

如果能把RemoteConfig.loadJson改成挂起函数,代码会更简洁易读,还能避免回调嵌套:

// 先重构RemoteConfig,把回调式改成挂起函数
suspend fun RemoteConfig.loadJsonSuspend(endpoint: String): List<Route> {
    // 这里实现HTTP请求逻辑,直接返回结果,异常则抛出
}

@Composable
fun Schedule() {
    var textToShow by remember { mutableStateOf("loading...") }

    LaunchedEffect(Unit) {
        try {
            val routes = RemoteConfig.loadJsonSuspend("schedule.api")
            textToShow = routes[1].jsonObject.toString()
        } catch (e: Exception) {
            textToShow = "Failed to load bus schedule. ($e)"
        }
    }

    Text(textToShow)
}

内容的提问来源于stack exchange,提问作者wdeb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 08:25:10