compose-hooks

ComposeHooks 项目使用指南 - 为 Jetpack Compose/Compose Multiplatform 提供 React Hooks 风格的状态管理和副作用处理。 使用此技能当需要:(1) 在 Compose 中管理组件状态 (useState, useGetState, useReducer), (2) 处理副作用和生命周期 (useEffect, useMount, use

SKILL.md

GitHub

ComposeHooks 使用指南

ComposeHooks 是一个为 Jetpack Compose/Compose Multiplatform 设计的 Hooks 库,灵感来自 React Hooks 和 ahooks。

核心概念

公开的 useXxx Hook 均提供对应的 rememberXxx 别名,选择你喜欢的命名风格。少数历史 API(如 Table.useTableInstance)仅为兼容保留,优先使用顶层 useXxx/rememberXxx。

平台支持

库以 Kotlin Multiplatform 形式发布(artifact id hooks2),覆盖四个目标:

平台 target 说明
Android androidTarget 含平台专属 hooks(生物识别、网络、电池、传感器等)
Desktop jvm 桌面专属 useKeyPress
iOS iosArm64 / iosSimulatorArm64 / iosX64 状态/副作用/网络等通用 hooks
Web wasmJs (browser) 自 2.4.0 起可用,用于在浏览器中运行 Compose 组件

wasmJs 注意事项:

  • commonMain 中的 hooks 全部可用;平台强相关 hooks(Android 专属、usePersistent 的存储后端等)需在各 target 的 actual 实现中处理或降级。
  • useRequest/useForm/useRedux 使用的 KClass 仅作 Map 键,wasmJs 下可用;真正的反射调用(.call/.callSuspend/.createType)已隔离在 commonJvmAndroid,不影响 wasmJs 编译。
  • usePersistent 采用注入式设计(SaveToPersistent<T> 函数类型),wasmJs 下可注入基于 localStorage 的实现。

快速参考

状态管理 Hooks

Hook 用途 示例
useState 基础状态管理(推荐用 by 委托);派生状态重载 useState(keys) { } 封装 derivedStateOf var state by useState("") / val full by useState(first, last) { "$first $last" }
useStateAsync 异步初始化状态 val state = useStateAsync { fetchDefault() }
useGetState 解构使用的状态管理(推荐) val (state, setState, getState) = useGetState(0)
useControllable 受控/非受控组件 val (state, setValue) = useControllable(default)
useResetState 带重置功能的状态 val (state, setState, reset) = useResetState("init")
useBoolean 布尔状态管理 val (state, toggle, set, setTrue, setFalse) = useBoolean(false)
useToggle 两值切换 val (state, toggle) = useToggle("A", "B")
useToggleEither 不同类型切换 val (state, toggle) = useToggleEither("left", 100)
useToggleVisible 切换内容可见性 val (content, toggle) = useToggleVisible { Text("Hi") }
useReducer Redux 风格状态管理 val (state, dispatch) = useReducer(reducer, initialState)
useRef 不触发重组的引用 val ref = useRef(0)
useCreation 创建复杂对象(类似 useMemo),返回 Ref<T> val obj by useCreation { ExpensiveObj() }
usePersistent 轻量级持久化状态 val (state, setState) = usePersistent("key", "default")
usePrevious 获取前一个值 val prev = usePrevious(state)
useLatestRef 始终返回最新值的引用 val ref = useLatestRef(state)
useLatestState 始终返回最新值的 State<T> val latest by useLatestState(value)
useLastChanged 最后变更时间 val time = useLastChanged(source)
useAutoReset 自动重置状态 var state by useAutoReset("default", 3.seconds)

集合 Hooks

Hook 用途 示例
useList 列表状态管理 val list = useList(1, 2, 3)
useListReduce 列表聚合 val sum by useListReduce(list) { a, b -> a + b }
useMap Map 状态管理 val map = useMap("key" to "value")
useImmutableList 不可变列表 val (list, mutate) = useImmutableList(1, 2, 3)
useImmutableListReduce 不可变列表聚合 val sum by useImmutableListReduce(list) { a, b -> a + b }
useSorted 列表排序 val sorted by useSorted(list) { a, b -> a.compareTo(b) }
useCycleList 循环列表 val (current, index, next, prev, go) = useCycleList(persistentListOf("A","B","C"))
useSelectable 选择/多选 val (selectedItems, isSelected, toggleSelected) = useSelectable(...)

数值 Hooks

Hook 用途 示例
useInt Int 状态 val count = useInt(0)
useLong Long 状态 val id = useLong(0L)
useFloat Float 状态 val ratio = useFloat(0f)
useDouble Double 状态 val price = useDouble(0.0)
useCounter 计数器 val (count, inc, dec, set, reset) = useCounter(0)

副作用 Hooks

Hook 用途 示例
useEffect 副作用处理 useEffect(dep) { /* effect */ }
useMount 组件挂载时执行 useMount { loadData() }
useUnmount 组件卸载时执行 useUnmount { cleanup() }
useUnmountedRef 是否已卸载 val unmounted = useUnmountedRef()
useUpdateEffect 跳过首次执行的 Effect useUpdateEffect(dep) { /* effect */ }
usePausableEffect 可暂停/停止的 Effect val (stop, pause, resume) = usePausableEffect(dep) { }
useDebounceEffect 防抖 Effect useDebounceEffect(dep) { /* 500ms后执行 */ }
useThrottleEffect 节流 Effect useThrottleEffect(dep) { /* 限频执行 */ }
useBackToFrontEffect 应用回到前台(Android) useBackToFrontEffect { refreshData() }
useFrontToBackEffect 应用进入后台(Android) useFrontToBackEffect { saveState() }

防抖与节流

Hook 用途 示例
useDebounce 防抖值 val debounced = useDebounce(value)
useDebounceFn 防抖函数 val fn = useDebounceFn<String>({ search(it) })
useThrottle 节流值 val throttled = useThrottle(value)
useThrottleFn 节流函数 val fn = useThrottleFn<Int>({ log(it) })

定时器与延迟

Hook 用途 示例
useInterval 定时器 useInterval(optionsOf = { period = 1.seconds }) { tick() }
useTimeout 延时执行(已废弃,优先用 useTimeoutFn) useTimeout(3.seconds) { showNotification() }
useTimeoutFn 延时执行(可控) val (pending, start, stop) = useTimeoutFn(fn, 3.seconds)
useTimeoutPoll 超时轮询 useTimeoutPoll({ fetchData() }, 5.seconds)
useCountdown 倒计时 val (remain, formatted) = useCountdown { targetDate = ... }

时间与日期

Hook 用途 示例
useNow 当前时间(定时更新) val now = useNow { interval = 1.seconds }
useTimestamp 时间戳(定时更新) val (ts, pause, resume) = useTimestamp { interval = 100.milliseconds }
useTimestampRef 时间戳 Ref 版本 val (ref, pause, resume) = useTimestampRef { interval = 100.milliseconds }
useDateFormat 日期格式化 val formatted = useDateFormat(instant, "YYYY-MM-DD")
useTimeAgo 相对时间 val ago = useTimeAgo(pastInstant)

数学运算

Hook 用途 示例
useAbs 绝对值 val abs = useAbs(value)
useCeil 向上取整 val ceil = useCeil(value)
useFloor 向下取整 val floor = useFloor(value)
useRound 四舍五入 val round = useRound(value)
useTrunc 截断 val trunc = useTrunc(value)
useMin/useMax 最小/最大值 val min = useMin(a, b)
usePow 幂运算 val pow = usePow(base, exp)
useSqrt 平方根 val sqrt = useSqrt(value)

异步

Hook 用途 示例
useAsync 简化协程 val run = useAsync { fetchData() }
useCancelableAsync 可取消协程 val (run, cancel, isActive) = useCancelableAsync()
useMemoizedFn 记忆化递归函数 val fn = useMemoizedFn<T, R> { ... }

组件通信

Hook 用途 示例
useContext 跨组件共享状态 val theme = useContext(ThemeContext)
useEventSubscribe 事件订阅 useEventSubscribe<MyEvent> { handle(it) }
useEventPublish 事件发布 val publish = useEventPublish<MyEvent>()
useUpdate 强制重组 val forceUpdate = useUpdate()

网络请求

Hook 用途 示例
useRequest 网络请求管理 val (data, loading, error, request) = useRequest(requestFn)
useSse SSE 流式连接 val (data, streaming, error, _, send, cancel) = useSse(streamFn)

全局状态管理

Hook 用途 示例
useSelector 从 Store 选择状态 val count by useSelector<AppState, Int> { count }
useDispatch 获取 dispatch 函数 val dispatch = useDispatch<AppAction>()
useDispatchAsync 异步 dispatch val dispatchAsync = useDispatchAsync<AppAction>()
useStateMachine 状态机 val (state, send) = useStateMachine(graph)

撤销/重做

Hook 用途 示例
useUndo 撤销/重做 val (state, set, reset, undo, redo) = useUndo(initial)

UI 相关

Hook 用途 示例
useClipboard 剪贴板操作 val (copy, paste) = useClipboard()
useKeyboard 软键盘显隐控制 val (hideKeyboard, showKeyboard) = useKeyboard()

表单 Hooks

Hook 用途 示例
Form.useForm 表单实例 val form = Form.useForm()
Form.useWatch 监听表单值 val value = Form.useWatch("field", form)
Form.useFormInstance 获取表单实例 val form = Form.useFormInstance()

表格 Hooks

Hook 用途 示例
useTable 无头表格 val table = useTable(data, columns) { ... }
useTableRequest 分页请求表格 val tableReq = useTableRequest(requestFn)

平台专属 Hooks

Android

Hook 用途 示例
useBiometric 生物识别 val (openBiometric, isAuthed) = useBiometric()
useNetwork 网络状态 val network by useNetwork()
useBatteryInfo 电池信息 val battery by useBatteryInfo()
useBuildInfo 设备信息 val build = useBuildInfo()
useScreenInfo 屏幕信息 val screen = useScreenInfo()
useVibrate 振动 val (shortVibrate, longVibrate) = useVibrate()
useFlashlight 手电筒 val (turnOn, turnOff) = useFlashlight()
useWakeLock 唤醒锁 val (request, release, isActive) = useWakeLock()
useSensor 传感器 useSensor(Sensor.TYPE_ACCELEROMETER) { event -> ... }
useIlluminance 光照强度 val illuminance = useIlluminance()
useIdle 空闲检测 val idle = useIdle()
useScreenBrightness 屏幕亮度 val (setBrightness, initialBrightness) = useScreenBrightness()
useDisableScreenshot 禁用截图 val (disable, enable, isDisabled) = useDisableScreenshot()
useWindowFlags 窗口标志 val (add, clear, isAdded) = useWindowFlags(key, flags)

Desktop

Hook 用途 示例
useKeyPress 键盘按键检测 useKeyPress(Key.Enter) { handleEnter() }

详细参考

常见模式

1. 受控组件

// 推荐:使用 useGetState 解构
val (text, setText) = useGetState("")
OutlinedTextField(
    value = text.value,
    onValueChange = setText,
    label = { Text("输入") }
)

// 或使用 by 委托
var text by useState("")
OutlinedTextField(
    value = text,
    onValueChange = { text = it },
    label = { Text("输入") }
)

2. 解决闭包问题(来自 UseStateExample.kt)

// 方式1: 使用 useGetState 函数式更新
val (state, setState) = useGetState("initial")
LaunchedEffect(Unit) {
    repeat(10) {
        delay(1.seconds)
        setState { "$it." }  // 函数式更新,避免闭包问题
    }
}

// 方式2: 使用 by 委托
var byState by useState("initial")
LaunchedEffect(Unit) {
    repeat(10) {
        delay(1.seconds)
        byState += "."  // 直接修改,无闭包问题
    }
}

// 方式3: 使用 useLatestRef
val (state, setState) = useState("initial")
val stateRef = useLatestRef(state)
LaunchedEffect(Unit) {
    repeat(10) {
        delay(1.seconds)
        setState("${stateRef.current}.")  // 通过 ref 获取最新值
    }
}

3. 网络请求(来自 Auto&Manual.kt)

// 自动请求
val (userInfoState, loadingState, errorState) = useRequest(
    requestFn = { NetApi.userInfo(it) },
    optionsOf = {
        defaultParams = "junerver"  // 自动请求必须设置默认参数
    }
)
val userInfo by userInfoState
val loading by loadingState

if (loading) {
    Text(text = "loading ...")
}
userInfo?.let { Text(text = it.toString()) }

// 手动请求
val (repoInfoState, loadingState, errorState, request) = useRequest(
    requestFn = { it: Tuple2<String, String> ->
        NetApi.repoInfo(it.first, it.second)
    },
    optionsOf = {
        manual = true
        defaultParams = tuple("junerver", "ComposeHooks")
    }
)
TButton(text = "request") { request() }

4. Redux 风格状态管理(来自 UseReducerExample.kt)

// 定义 State 和 Action
data class SimpleData(val name: String, val age: Int)

sealed interface SimpleAction {
    data class ChangeName(val newName: String) : SimpleAction
    data object AgeIncrease : SimpleAction
}

// 定义 Reducer
val simpleReducer: Reducer<SimpleData, SimpleAction> = { prevState, action ->
    when (action) {
        is SimpleAction.ChangeName -> prevState.copy(name = action.newName)
        is SimpleAction.AgeIncrease -> prevState.copy(age = prevState.age + 1)
    }
}

// 使用
val (state, dispatch) = useReducer(
    simpleReducer,
    initialState = SimpleData("default", 18),
    middlewares = arrayOf(logMiddleware())
)

TButton(text = "Change Name") { dispatch(SimpleAction.ChangeName("Alice")) }
TButton(text = "Increase Age") { dispatch(SimpleAction.AgeIncrease) }
Text(text = "State: ${state.value}")

5. 列表操作(来自 UseListExample.kt)

val listState = useList(1, 2, 3)

// 操作方法
listState.add(4)              // 添加
listState.add(0, 0)           // 插入
listState.removeAt(0)         // 删除
listState.removeLast()        // 删除最后一个
listState[0] = 10             // 修改
listState.clear()             // 清空
listState.shuffle()           // 打乱

// 配合 useListReduce
val sum by useListReduce(listState) { a, b -> a + b }

6. 防抖输入(来自 UseDebounceExample.kt)

var inputValue by useState("")
val debouncedValue by useDebounce(
    value = inputValue,
    optionsOf = {
        wait = 500.milliseconds
    }
)

OutlinedTextField(
    value = inputValue,
    onValueChange = { inputValue = it },
    label = { Text("Type something...") }
)

Text(text = "Debounced: $debouncedValue")

7. SSE 流式连接

// 自动连接
val (lastEvent, isStreaming, error) = useSse(
    streamFn = { params: String -> sseService.subscribe(params) },
    optionsOf = {
        defaultParams = "topic-1"
        onEvent = { event -> println("收到: $event") }
    }
)

// 手动连接
val (lastEvent, isStreaming, error, params, send, cancel) = useSse(
    streamFn = { url: String -> sseClient.connect(url) },
    optionsOf = { manual = true }
)
Button(onClick = { send("https://api.example.com/events") }) {
    Text("开始监听")
}