Install to Claude Code
npx -y skills add junerver/ComposeHooks --skill compose-hooksDescription
|
SKILL.md
---
name: compose-hooks
description: |
ComposeHooks 项目使用指南 - 为 Jetpack Compose/Compose Multiplatform 提供 React Hooks 风格的状态管理和副作用处理。
使用此技能当需要:(1) 在 Compose 中管理组件状态 (useState, useGetState, useReducer),
(2) 处理副作用和生命周期 (useEffect, useMount, useUnmount),
(3) 管理网络请求 (useRequest),(4) 使用防抖/节流 (useDebounce, useThrottle),
(5) 管理列表/Map状态 (useList, useMap),(6) 使用定时器 (useInterval, useTimeoutFn/useTimeoutPoll/useCountdown),
(7) 全局状态管理 (useSelector, useDispatch),(8) 使用无头表格 (useTable/useTableRequest)。
关键词: Compose, Hooks, 状态管理, useRequest, useReducer, useState, useEffect
---
# 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() }` |
## 详细参考
- **状态管理 Hooks**: 见 [references/state-hooks.md](references/state-hooks.md)
- **副作用 Hooks**: 见 [references/effect-hooks.md](references/effect-hooks.md)
- **工具 Hooks**: 见 [references/utility-hooks.md](references/utility-hooks.md)
- **网络请求 Hooks**: 见 [references/request-hooks.md](references/request-hooks.md)
- **Table 相关 Hooks**: 见 [references/table-hooks.md](references/table-hooks.md)
- **表单 Hooks**: 见 [references/form-hooks.md](references/form-hooks.md)
- **SSE 流式连接**: 见 [references/sse-hooks.md](references/sse-hooks.md)
- **平台专属 Hooks**: 见 [references/platform-hooks.md](references/platform-hooks.md)
- **remember 别名索引**: 见 [references/remember-aliases.md](references/remember-aliases.md)
## 常见模式
### 1. 受控组件
```kotlin
// 推荐:使用 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)
```kotlin
// 方式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)
```kotlin
// 自动请求
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)
```kotlin
// 定义 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)
```kotlin
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)
```kotlin
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 流式连接
```kotlin
// 自动连接
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("开始监听")
}
```
