如何构建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
相关产品推荐
相关产品推荐

