compose-hooks logo

compose-hooks

|

SKILL.md

Full skill instructions

ComposeHooks 使用指南

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

核心概念

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

平台支持

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

平台target说明
AndroidandroidTarget含平台专属 hooks(生物识别、网络、电池、传感器等)
Desktopjvm桌面专属 useKeyPress
iOSiosArm64 / iosSimulatorArm64 / iosX64状态/副作用/网络等通用 hooks
WebwasmJs (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) { } 封装 derivedStateOfvar 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") }
useReducerRedux 风格状态管理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 }
useMapMap 状态管理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用途示例
useIntInt 状态val count = useInt(0)
useLongLong 状态val id = useLong(0L)
useFloatFloat 状态val ratio = useFloat(0f)
useDoubleDouble 状态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跳过首次执行的 EffectuseUpdateEffect(dep) { /* effect */ }
usePausableEffect可暂停/停止的 Effectval (stop, pause, resume) = usePausableEffect(dep) { }
useDebounceEffect防抖 EffectuseDebounceEffect(dep) { /* 500ms后执行 */ }
useThrottleEffect节流 EffectuseThrottleEffect(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延时执行(已废弃,优先用 useTimeoutFnuseTimeout(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)
useSseSSE 流式连接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异步 dispatchval 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("开始监听")
}