写在前面
本文中提及的use
开头的函数,都出自与我的 ComposeHooks 项目,它提供了一系列 React Hooks 风格的状态封装函数,可以帮你更好的使用 Compose,无需关系复杂的状态管理,专心于业务与UI组件。
这是系列文章的第一篇,全部文章:
- 在Compose中使用useRequest轻松管理网络请求
- 在Compose中使用状态提升?我提升个P...Provider
- 在Compose中父组件如何调用子组件的函数?
- 在Compose中方便的使用MVI思想?试试useReducer!
还记得: 使用 ahooks 中的 useRequest 轻松管理React中的网络请求 这篇文章么?
现在我将 ahooks 带到了 Compose 开发中!
在Compose项目中,你是如何进行网络请求,管理状态的?ViewModel
?还是 LaunchedEffect
配合 State
?
他们看起来都不够优雅,我们真的需要在 Compose 中创建这么多VM么?
还有更优雅的方式么?
来了解一下 junerver/ComposeHooks 吧,也许它会让你在 Compose 开发中更加得心应手,更多的专注于组件而非复杂的状态管理。
来试试 useRequest
吧
一句话发起请求:
val (data, loading, error, request) = useRequest(::fn.asSuspendNoopFn())
useRequest
的第一个参数是一个 suspend
函数,在组件初次加载时,会自动触发该函数执行。同时自动管理该函数的 loading
, data
, error
等状态。
hooks2 更新说明:现在
data
、loading
、error
是State
包装的状态,在组件中如果要使用他们的值,需要通过state.value
来获取(或者使用by
委托获取)。
手动触发/自动触发
useRequest
的第二个参数是配置选项,我们可以使用optionsOf
轻松的自定义请求的相关配置,例如设置手动触发:
// 需要导入 invoke函数
import xyz.junerver.compose.hooks.invoke
// 这是一个模拟网络请求的suspend函数
suspend fun fn(s1: String, s2: String): String {
delay(2_000)
return "response: result success+${Random.nextInt(20)}"
}
@Composable
fun TestRequestComponent() {
val (data, loading, error, request) = useRequest(
requestFn = ::fn.asSuspendNoopFn(), //普通的挂起函数需要转换成钩子的参数
optionsOf = {
manual = true
})
Button(onClick = { request("1", "2") }) {
Text(text = "手动请求")
}
}
此时我们的请求不再自动执行,当需要发起请求时直接调用 request
,并传递参数。
通过对 useRequest
返回值解构声明或得到的 request
函数是一个普通函数,我们可以直接在组件中使用,无需关心协程作用域的问题。
manual
参数的默认值是 false
,如果你需要在组件挂载后自动请求,那么直接忽视即可。
错误重试
当我们的网络请求出错时,一般都需要进行错误重试的工作,在 ComposeHooks 中这个操作变得非常简单。
对上面的配置增加一行代码,配置最大重试次数:retryCount = 3
,你的请求函数会在出错后自动重试。
val (data, loading, error, request) = useRequest(
requestFn = ::fn.asSuspendNoopFn(),
optionsOf = {
retryCount = 3
})
轮询
同样只需要添加一行代码:pollingInterval = 2.seconds
,现在你的请求将会每隔两秒自动发出
val (data, loading, error, request) = useRequest(
requestFn = ::fn.asSuspendNoopFn(),
optionsOf = {
pollingInterval = 2.seconds
})
防抖、节流
只需要简单的配置 debounceOptions
与 throttleOptions
参数,即可为 request
函数增加防抖或节流的效果,非常简单方便。
val (data, loading, error, request) = useRequest(
requestFn = ::fn.asSuspendNoopFn(),
optionsOf = {
manual = true
debounceOptionsOf = {
wait = 2.seconds //两秒防抖间隔
}
})
mutate
立即变更数据
useRequest
提供了 mutate
函数, 支持立即修改 useRequest
返回的 data
状态。
val (userInfo, loading, _, _, mutate) = useRequest(
requestFn = { NetApi.userInfo(it[0] as String) },
optionsOf = {
defaultParams = arrayOf("junerver")
}
)
TButton(text = "changeName") {
// 你可以在发起修改的同时,使用 mutate 进行乐观更新
mockFnChangeName(newName) // 在这里发起网络请求
if (userInfo.value != null) {
mutate { // 发起请求的同时本地调用mutate修改状态
it!!.copy(name = input)
}
}
}
mutate
函数的签名是:fun mutate(mutateFn: (TData?) -> TData)
mutate
函数可以帮我们轻松进行乐观更新!
探索更多
项目开源地址:junerver/ComposeHooks
MavenCentral:hooks2
// CMP 项目依赖
implementation("xyz.junerver.compose:hooks2:<latest_release>")
// 纯 Android 项目依赖
implementation("xyz.junerver.compose:hooks2-android:<latest_release>")
欢迎使用、勘误、pr。