English | 简体中文
注意:工件id为
hooks2
implementation("xyz.junerver.compose:hooks2:<latest_release>")目前只支持有限的 target:
- android
- desktop(jvm)
- iosarm64
- iosimulatorarm64
- iosx64
项目的 idea 来自 alibaba/hooks,这是一个非常好用的React Hooks 集合。
它封装了大多数的常用操作作为自定义钩子,而 useRequest 则是重中之重,它设计的非常轻量化、可配置性高,使用简单。
于是,参照这一设计思想,采用类似的 API 名称创建了可以用在 Compose 项目的 Hooks。
目前已经实现的钩子如下:
注意:所有 use 函数同样有 remember 的签名,如果你更喜欢 Compose 的命名方式,只需要使用 rememberXxx 即可!
| Hook 名称 | 描述 |
|---|---|
| useAutoReset | 一个会在一段时间后将状态重置为默认值的 Hook。 |
| useBoolean | 用于管理布尔状态的 Hook。 |
| useContext | 类似于 React 的 useContext。 |
| useCreation | useCreation 是 useRef 的替代品。 |
| useDebounce | 处理防抖值的 Hook。 |
| Form.useForm | 一个可以更轻松地控制无头组件 Form 的 Hook。 |
| useGetState | 使用解构声明语法处理状态的 Hook。 |
| useImmutableList | 一个用于在 Compose 中管理不可变列表的 Hook。 |
| useLastChanged | 一个记录上次更改时间的 Hook。 |
| useLatest | 一个返回最新值,有效避免闭包问题的 Hook。 |
| usePersistent | 一个轻量级持久化 Hook,你需要自己实现持久化方法(默认使用内存持久化)。 |
| usePrevious | 一个返回前一个状态的 Hook。 |
| useReducer | 类似于 React 的 useReducer。 |
| useRef | 类似于 React 的 useRef。 |
| useResetState | 一个用于管理带重置功能状态的 Hook。 |
| useSelectable | 一个帮助实现选择或多选功能的实用函数。 |
useSelector/useDispatch |
更容易管理全局状态,类似于 Redux-React。 |
| useState | 类似于 React 的 useState。 |
| useStateMachine | 一个用于管理状态机的 Compose Hook。 |
| useThrottle | 处理节流值的 Hook。 |
| useToggle | 一个用于切换状态的 Hook。 |
| Hook 名称 | 描述 |
|---|---|
useBackToFrontEffect & useFrontToBackEffect |
当应用进入后台或回到前台时执行 Effect。 |
| useEffect | 类似于 React 的 useEffect。 |
| useDebounceEffect | 对 useEffect 进行防抖。 |
| useThrottleEffect | 对 useEffect 进行节流。 |
| useUpdateEffect | 一个类似于 useEffect 但跳过第一次运行的 Hook。 |
| usePausableEffect | 一个可暂停的 Effect Hook,提供暂停、恢复和停止 Effect 执行的能力。 |
| Hook 名称 | 描述 |
|---|---|
| useMount | 一个在组件挂载后执行函数的 Hook。 |
| useUnmount | 一个在组件卸载前执行函数的 Hook。 |
| Hook 名称 | 描述 |
|---|---|
| useDateFormat | 受dayjs启发,根据传递的令牌对日期进行格式化的 Hook。 |
| useInterval | 一个处理 setInterval 定时器函数的 Hook。 |
| useNow | 一个返回当前日期时间的 Hook,默认格式为 yyyy-MM-dd HH:mm:ss。 |
| useTimeAgo | 响应式时间戳。当时间变化时自动更新“距离现在多久”的字符串。 |
| useTimeout | 一个处理 setTimeout 定时器函数的 Hook。 |
| useTimeoutFn | 一个用于在指定延迟后执行函数并提供控制功能的 Hook。 |
| useTimeoutPoll | 使用超时来轮询内容。在最后一个任务完成后触发回调。 |
| useTimestamp | 一个返回当前时间戳作为响应式状态的 Hook。 |
| Hook 名称 | 描述 |
|---|---|
useAbs |
响应式 kotlin.math.abs。 |
useCeil |
响应式 kotlin.math.ceil。 |
useRound |
响应式 kotlin.math.round。 |
useTrunc |
响应式 kotlin.math.truncate。 |
useMin |
响应式 kotlin.math.min。 |
useMax |
响应式 kotlin.math.max。 |
usePow |
响应式 kotlin.math.pow。 |
useSqrt |
响应式 kotlin.math.sqrt。 |
| Hook 名称 | 描述 |
|---|---|
| useAsync | 一个封装 rememberCoroutineScope 以简化协程使用的 Hook。 |
| useBiometric* | 方便地使用生物识别功能。 |
| useBatteryInfo* | 一个可以获取电池电量和是否正在充电的 Hook。 |
| useBuildInfo* | 一个可以获取 Android 品牌、型号和版本的 Hook。 |
| useClipboard | 易于使用的剪贴板 Hook。 |
| useCountdown | 一个用于管理倒计时的 Hook。 |
| useCounter | 一个用于管理计数器的 Hook。 |
| useCycleList | 循环遍历列表项的 Hook。 |
| useDebounceFn | 处理防抖函数的 Hook。 |
| useDisableScreenshot* | 一个用于处理隐私页面禁止截图的 Hook。 |
| useEvent | 使用订阅-发布模式实现轻量级跨组件通信。 |
| useFlashlight* | 一个方便使用手电筒的 Hook。 |
| useIdel | 跟踪用户是否处于非活动状态。 |
useKeyboard |
一个控制软键盘显示和隐藏的 Hook。 |
| useNetwork* | 一个用于获取网络连接状态和类型的 Hook。 |
| useRequest | 管理网络请求并实现:手动和自动 触发;生命周期回调;刷新;修改变化;取消请求; 轮询; Ready; 依赖刷新; 防抖, 节流; 错误重试; |
| useScreenInfo* | 一个获取屏幕宽度、高度、横向和纵向方向信息的 Hook。 |
| useSorted | 一个处理列表排序的 Hook。 |
| useThrottleFn | 一个处理节流函数的 Hook。 |
| useUndo | 一个用于处理撤销和重做的 Hook。 |
| useUpdate | 一个返回可以强制组件重新渲染的函数的 Hook。 |
| useVibrate* | 一个让振动反馈变得简单的 Hook。 |
注意,标记
*的函数,只可以在 Android 中使用
独立的 AI 模块,提供与 OpenAI 兼容 API 和 Anthropic Messages API 进行 AI 聊天与结构化数据生成的 Hook。
添加 AI 模块依赖:
implementation("xyz.junerver.compose:hai:<latest_release>")| Hook 名称 | 描述 |
|---|---|
| useChat | 用于管理与 OpenAI 兼容 API 和 Anthropic Messages API 聊天对话的 Hook,支持流式响应的打字机效果。 |
| useAgent | 用于多轮工具调用(agent loop)的 Hook(构建在 useChat 之上)。 |
| useGenerateObject | 用于从 AI 响应生成结构化数据对象的 Hook,支持流式与增量更新对象。 |
功能特性:
- 流式响应 (SSE),实时打字机效果
- 支持非流式模式(
stream = false) - 多模态输入支持(文本、图片、文件)
- 类型安全的结构化数据生成
- 消息状态管理
- 加载和错误状态
- 控制函数(发送、停止、重新加载)
- 可配置选项(temperature、maxTokens、timeout 等)
- 生命周期回调(onFinish、onError、onStream)
示例 - 聊天对话:
val (messages, isLoading, error, sendMessage, _, _, reload, stop) = useChat {
provider = Providers.OpenAI(apiKey = "your-api-key")
model = "gpt-3.5-turbo"
systemPrompt = "你是一个乐于助人的助手。"
onFinish = { message, usage, reason ->
println("完成: ${message.content}")
}
}
// 发送消息
sendMessage("你好!")
// 显示消息(带流式效果)
messages.value.forEach { message ->
Text("${message.role}: ${message.content}")
}示例 - 生成结构化数据:
@Serializable
data class Recipe(val name: String, val ingredients: List<String>)
val (recipe, rawJson, isLoading, error, submit, stop) = useGenerateObject<Recipe>(
schema = Recipe::class.jsonSchemaString,
) {
provider = Providers.OpenAI(apiKey = "your-api-key")
systemPrompt = "你是一位专业的厨师。"
}
// 生成结构化数据
submit("生成一道意大利面的食谱")
// 使用结果
recipe.value?.let { r ->
Text("食谱: ${r.name}")
r.ingredients.forEach { Text("- $it") }
}KMP项目
// groovy
implementation 'xyz.junerver.compose:hooks2:<latest_release>'
// kotlin
implementation("xyz.junerver.compose:hooks2:<latest_release>")
纯 Android 项目引入 hooks2
纯Android项目请使用如下依赖(即工件id:hooks2-android):
implementation("xyz.junerver.compose:hooks2-android:<latest_release>")旧版本 hooks 继续支持
如果你的项目并没有出现因为重组导致性能问题,你可以继续在 Android项目 中使用旧版本,后续开发中会同步 bugfix 到旧版本。
implementation("xyz.junerver.compose:hooks:2.0.3")-
使用
useGetState快速创建受控组件val (name, setName, getState) = useGetState("") OutlinedTextField( value = getName(), // or `name.value` onValueChange = setName, label = { Text("Input Name") } )
-
使用
useEffect执行组件副作用 -
使用
useRef创建不受组件重组影响的对象引用val countRef = useRef(0) // or `val countRef by useRef(0)` Button(onClick = { countRef.current += 1 // or `countRef += 1` println(countRef) }) { Text(text = "Ref= ${countRef.current}") // or `countRef` }
-
使用
useRequest轻松管理网络状态val (dataState, loadingState, errorState, run) = useRequest( requestFn = WebService::login.asRequestFn(), //自行封装相应扩展函数 optionsOf { manual = true } ) val data by dataState // 使用委托获取状态的值 val loading by loadingState val error by errorState if (loading) { Text(text = "loading ....") } if (data != null) { Text(text = "resp: $data") } if (error != null) { Text(text = "error: $error") } Button(onClick = { run(arrayOf(requestBody)) }) { Text(text = "Login") }
useRequest通过插件式组织代码,核心代码极其简单,并且可以很方便的扩展出更高级的功能。目前已有能力包括:- 自动请求/手动请求
- 轮询
- 防抖
- 节流
- 错误重试
- loading delay
- SWR(stale-while-revalidate)
- 缓存
更多用法请查看wiki、工程示例
复制Live Templates目录下的hooks
文件,粘贴到C:\Users\<user-name>\AppData\Roaming\Google\AndroidStudio2023.2\templates\
你可以方便的通过 us、ur 来创建 useState、useRequest的代码片段。
像useRequest这样的钩子,它的返回值可以解构出很多对象、函数,开启 InlayHint 很有必要:
Editor - Inlay Hints - Types - Kotlin
如果你的项目需要使用 ProGuard,请加入下面的混淆规则:
-keep class xyz.junerver.composehooks.** { *; }
-keepclassmembers class xyz.junerver.composehooks.** { *; }
-dontwarn xyz.junerver.composehooks.**
- 在Compose中使用useRequest轻松管理网络请求
- 在Compose中使用状态提升?我提升个P...Provider
- 在Compose中父组件如何调用子组件的函数?
- 在Compose中方便的使用MVI思想?试试useReducer!
- 在Compose中像使用redux一样轻松管理全局状态
- 在Compose中轻松使用异步dispatch管理全局状态
- 在Compose中管理网络请求竟然如此简单!
- 在Jetpack Compose中优雅的使用防抖、节流
KMP friendlyCI- Unit Test
- Complete documentation