Skip to content

Latest commit

 

History

History
374 lines (289 loc) · 27.7 KB

File metadata and controls

374 lines (289 loc) · 27.7 KB

ComposeHooks

English | 简体中文

License Version maven-central latest releast stars Average time to resolve an issue Percentage of issues still open Ask DeepWiki klibs.io

Star History

Star History Chart

KMP 支持

注意:工件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 即可!

Hooks

State

Hook 名称 描述
useAutoReset 一个会在一段时间后将状态重置为默认值的 Hook。
useBoolean 用于管理布尔状态的 Hook。
useContext 类似于 React 的 useContext
useCreation useCreationuseRef 的替代品。
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。

Effect

Hook 名称 描述
useBackToFrontEffect & useFrontToBackEffect 当应用进入后台或回到前台时执行 Effect。
useEffect 类似于 React 的 useEffect
useDebounceEffect useEffect 进行防抖。
useThrottleEffect useEffect 进行节流。
useUpdateEffect 一个类似于 useEffect 但跳过第一次运行的 Hook。
usePausableEffect 一个可暂停的 Effect Hook,提供暂停、恢复和停止 Effect 执行的能力。

LifeCycle

Hook 名称 描述
useMount 一个在组件挂载后执行函数的 Hook。
useUnmount 一个在组件卸载前执行函数的 Hook。

Time

Hook 名称 描述
useDateFormat dayjs启发,根据传递的令牌对日期进行格式化的 Hook。
useInterval 一个处理 setInterval 定时器函数的 Hook。
useNow 一个返回当前日期时间的 Hook,默认格式为 yyyy-MM-dd HH:mm:ss
useTimeAgo 响应式时间戳。当时间变化时自动更新“距离现在多久”的字符串。
useTimeout 一个处理 setTimeout 定时器函数的 Hook。
useTimeoutFn 一个用于在指定延迟后执行函数并提供控制功能的 Hook。
useTimeoutPoll 使用超时来轮询内容。在最后一个任务完成后触发回调。
useTimestamp 一个返回当前时间戳作为响应式状态的 Hook。

Math

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

Utilities

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 模块

独立的 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")

快速开始

  1. 使用 useGetState 快速创建受控组件

    val (name, setName, getState) = useGetState("")
    OutlinedTextField(
        value = getName(), // or `name.value`
        onValueChange = setName,
        label = { Text("Input Name") }
    )
  2. 使用 useEffect 执行组件副作用

  3. 使用 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`
    }
  4. 使用 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

复制Live Templates目录下的hooks 文件,粘贴到C:\Users\<user-name>\AppData\Roaming\Google\AndroidStudio2023.2\templates\

你可以方便的通过 usur 来创建 useStateuseRequest的代码片段。

开启类型的内嵌提示

useRequest这样的钩子,它的返回值可以解构出很多对象、函数,开启 InlayHint 很有必要:

Editor - Inlay Hints - Types - Kotlin

混淆

如果你的项目需要使用 ProGuard,请加入下面的混淆规则:

-keep class xyz.junerver.composehooks.** { *; }
-keepclassmembers class xyz.junerver.composehooks.** { *; }
-dontwarn xyz.junerver.composehooks.**

文档

Todo:

  • KMP friendly
  • CI
  • Unit Test
  • Complete documentation

参考

  1. alibaba/hooks
  2. pavi2410/useCompose
  3. vueuse/vueuse

贡献指南

Contributing guidelines

License

Apache License 2.0