Skip to content
Junerver Hou edited this page Jul 21, 2025 · 7 revisions

useState

useState 是对 remember { mutableStateOf() } 的封装,用来方便的在组件中使用状态。

请注意:非空状态使用 useState ,可空状态请使用 _useState,对于非空状态进行了一定的优化,如果是数值类型,将会使用对应的数值状态,而非 MutableState

var byState by useState("by delegate")
TButton(text = "change") {
    byState += "." // 使用方法一致
}

useState 还可以用来创建计算状态/派生状态,来代替使用 derivedStateOf

val canUndo = useState { state.value.past.isNotEmpty() }

如果你希望使用类似 React 的写法,你应该优先使用 useGetState

useAutoReset

一个用来定时恢复默认值的 Hook。

var state by useAutoReset(default = "default value", interval = 2.seconds)
Column {
    Text(text = state)
    TButton(text = "set value") {
        state = "has set new value"
    }
}

修改状态后开始延时 interval 设定的时间,时间结束后恢复未默认值。

useBoolean

管理 boolean 状态的 Hook。

你可以通过解构语法,轻松的获得多个用于管理 boolean 状态的函数:

val (state, toggle, setValue, setTrue, setFalse) = useBoolean(default = true)
  • 传递给函数的值 default 是初始的默认值
  • 通过 state 直接读取 boolean 的状态(State<Boolean>
  • toggle 函数用来切换状态
  • setValue 函数签名为 (Boolean) -> Unit,可以用来设置状态
  • setTrue 设置状态为 true
  • setFalse 设置状态为 false

useContext

useContext 是一个用于获取上下文值的 Hook。它接受一个由 createContext 创建的上下文对象,并返回该上下文的当前值。

val context = useContext(MyContext)

使用 useContext 可以避免复杂的状态提升,状态由父组件通过 ReactContext.Provider 提供,子组件无论嵌套多少级,都可以使用 useContext 轻松获取上下文。

// 创建上下文
val SimpleContext = createContext(
    tuple(
        initialState,
        { _: String -> },
        {},
    ),
)

// 在父组件中提供上下文
@Composable
fun ParentComponent() {
    val state = useState(initialValue)
    SimpleContext.Provider(tuple(state, updateFn, resetFn)) {
        ChildComponent()
    }
}

// 在子组件中使用上下文
@Composable
fun ChildComponent() {
    val (state, updateFn, resetFn) = useContext(SimpleContext)
    // 使用上下文中的值和函数
}

useCountdown

用来管理倒计时的 Hook。

var show by useState(default = false)    
val (leftTime, formattedRes) = useCountdown(
    optionsOf = {
        leftTime = 10.seconds
        // targetDate = Clock.System.now() + 10.seconds
        // interval = 3.seconds
        onEnd = {
            show = true
        }
    }
)
Text(text = "LeftTime: ${leftTime.value.inWholeSeconds}")
Text(text = formattedRes.value.toString())
if (show) {
    Text(text = "countdown on end!!", color = Color.Green)
}

通过设置 leftTimetargetDate 来配置倒计时的结束时间,使用 interval 配置倒计时间隔

返回值 leftTime 是剩余时间的状态,formattedRes 是格式化的时间,你可以自行使用该值来用于UI显示

data class FormattedRes(
    val days: Int,
    val hours: Int,
    val minutes: Int,
    val seconds: Int,
    val milliseconds: Int,
)

useCreation

useCreation 是一个用于创建持久化值的 Hook,类似于 useMemo,但它确保创建的值在依赖项不变时保持不变。

val instance by useCreation(dependency) {
    ExpensiveClass(dependency)
}

这个 Hook 在创建昂贵的实例或需要持久化的对象时特别有用,它只会在依赖项变化时重新创建值。

// 创建一个只在依赖项变化时重新创建的对象
val subject by useCreation(dependency) {
    Subject("Created with dependency: $dependency")
}

// 可以与 by 操作符一起使用,直接访问创建的值
Text(text = "Current instance: $subject")

useDebounce

useDebounce 是一个用于创建防抖动值的 Hook。它接受一个值和一个配置对象,并返回一个在指定时间后才更新的防抖动值。

val debouncedValue by useDebounce(
    value = inputValue,
    optionsOf = {
        wait = 500.milliseconds
        leading = false
        trailing = true
    }
)

这个 Hook 在处理频繁变化的输入(如搜索框)时特别有用,可以减少不必要的操作。

除了 useDebounce,还有两个相关的 Hook:

  • useDebounceFn: 创建一个防抖动函数
  • useDebounceEffect: 创建一个防抖动副作用

Form.useForm

Form.useForm 是一个用于创建和管理表单状态的 Hook。它提供了一组用于表单操作的函数和状态。

val form = Form.useForm()

返回的 form 对象包含以下函数和属性:

  • setFieldsValue: 设置表单字段的值
  • getFieldValue: 获取表单字段的值
  • getFieldsValue: 获取所有表单字段的值
  • resetFields: 重置表单字段
  • validateFields: 验证表单字段
  • submit: 提交表单

使用示例:

// 创建表单实例
val form = Form.useForm()

// 在表单中使用
Form(form) {
    // 表单字段
    FormItem(name = "name", label = "Name", rules = listOf(Required())) {
        OutlinedTextField(value = it, onValueChange = { value -> it = value })
    }
    
    // 表单操作
    TButton(text = "Submit") {
        form.validateFields { values, errors ->
            if (errors.isEmpty()) {
                // 处理表单提交
            }
        }
    }
}

useToggle

用于在两个状态值间切换的 Hook。

val (state, toggle) = useToggle("hello", "world")
val (either, toggleEither) = useToggleEither("example", Random.nextDouble())

Text(text = "current: $state")
TButton(text = "toggle") { toggle() }

Text(
    text = "either: ${
        either.fold(
            { "string: $it" },
            { "double: $it" }
        )
    }"
)
TButton(text = "toggle") { toggleEither() }

默认使用左值

useGetState

useGetState 的使用非常接近于 React 中的使用,在 Compose 中,如果你需要使用解构声明来获得接近 React 的开发体验,请务必使用 useGetState 而非 useState

使用示例:

import xyz.junerver.compose.hooks.invoke

val (state, setState) = useGetState(default)
fun set(num:Int) {
    setState(num)
}
fun add(){
	setState{ it +1 }
}

注意请务必手动导入 import xyz.junerver.compose.hooks.invoke

现在 set 函数的签名从 SetValueFn<T> 变更为 SetValueFn<SetterEither<T>>,如果你需要将 set 函数传递给受控组件,请使用 left 函数进行转换,或者使用 useControllable(它是 useGetState 的简化版本,专门用于受控组件,无需使用 left 函数进行转换)。

import xyz.junerver.compose.hooks.left

@Composable
private fun Copy() {
    val (state, setState) = useGetState("")
    val (copy, _) = useClipboard()
    Column {
        TextField(
            value = state.value,
            onValueChange = setState.left(), // 默认是 `SetValueFn<SetterEither<T>>` 不能直接传递给组件
            label = { Text("Text to copy") }
        )
        Button(onClick = { copy(state.value) }) {
            Text("Copy to clipboard")
        }
    }
}

useImmutableList

useImmutableList 是一个用于管理不可变列表的 Hook。它提供了一组用于操作不可变列表的函数,确保列表的不可变性。

val immutableListHolder = useImmutableList(1, 2, 3)
val immutableList by immutableListHolder.list

返回的 immutableListHolder 对象包含以下函数和属性:

  • list: 当前不可变列表的状态
  • mutate: 修改列表的函数,接受一个修改器函数
  • reset: 重置列表到初始状态

使用示例:

// 创建不可变列表
val immutableListHolder = useImmutableList(1, 2, 3)
val immutableList by immutableListHolder.list

// 修改列表
immutableListHolder.mutate {
    it.add(4) // 添加元素
    it.removeAt(0) // 删除元素
}

// 重置列表
immutableListHolder.reset()

useLastChanged

useLastChanged 是一个用于跟踪值最后更改时间的 Hook。它返回一个表示最后更改时间的 Instant 对象。

val lastChanged = useLastChanged(value)

这个 Hook 在需要跟踪值的变化时间时特别有用,例如显示"最后更新于"信息。

// 跟踪值的最后更改时间
val lastChanged = useLastChanged(value)

// 显示人类可读的时间差
val timeAgo = useTimeAgo(lastChanged)
Text(text = "Last updated: $timeAgo")

useLatestRef

useLatestRef 是一个用于获取最新值引用的 Hook。它返回一个始终包含最新值的引用对象。

val latestValue = useLatestRef(value)

这个 Hook 在异步操作中特别有用,可以确保始终访问到最新的值,而不是闭包捕获的旧值。

useRef

useRef 是一个用于创建可变引用的 Hook。它返回一个可变的引用对象,该对象在组件的整个生命周期内保持不变。

val ref = useRef(initialValue)

返回的 ref 对象有一个名为 current 的可变属性,可以用来保存任何值。修改 ref.current 不会触发组件的重新渲染。

// 创建引用
val countRef = useRef(0)

// 修改引用值
countRef.current++

// 访问引用值
Text(text = "Current ref value: ${countRef.current}")

// 提供了by委托的扩展函数,可以简化使用
var count by useRef(0)
count += 1

useRef 的主要用途:

  1. 存储不需要触发重新渲染的可变值
  2. 在异步操作中访问最新的状态或属性
  3. 保存对其他对象的引用

useResetState

useResetState 是一个带有重置功能的状态 Hook。它基于 useGetState 扩展,提供了一个额外的函数来将状态重置为初始值。

val (state, setState, getState, reset) = useResetState(initialValue)

返回的 reset 函数可以用来将状态重置为初始值,这在表单重置或需要恢复默认设置时特别有用。

// 创建可重置的状态
val (state, setState, _, reset) = useResetState("Initial value")

// 修改状态
setState("New value")

// 重置状态到初始值
reset()

useSelectable

useSelectable 是一个用于实现单选或多选功能的 Hook。它支持单选和多选两种模式,并提供了一组用于选择操作的函数。

val (selectedItems, isSelected, toggleSelected, selectAll, invertSelection, revertAll) = useSelectable(
    selectionMode, // SelectionMode.SingleSelect 或 SelectionMode.MultiSelect
    items,
    itemKeySelector
)

返回的元组包含以下内容:

  • selectedItems: 当前选中的项目列表
  • isSelected: 检查项目是否被选中的函数
  • toggleSelected: 切换项目选中状态的函数
  • selectAll: 选择所有项目的函数(仅多选模式)
  • invertSelection: 反转选择的函数(仅多选模式)
  • revertAll: 取消所有选择的函数

使用示例:

// 创建选择器
val (selectedItems, isSelected, toggleSelected, selectAll, invertSelection, revertAll) = useSelectable(
    SelectionMode.MultiSelect<String>(null),
    itemList,
    Item::id
)

// 在列表项中使用
LazyColumn {
    items(itemList) { item ->
        Row {
            Text(text = item.name)
            Checkbox(
                checked = isSelected(item.id),
                onCheckedChange = { toggleSelected(item.id) }
            )
        }
    }
}

// 操作按钮
Button(onClick = { selectAll() }) { Text("Select All") }
Button(onClick = { revertAll() }) { Text("Clear Selection") }

useStateMachine

useStateMachine 是一个用于管理状态机的 Hook。它提供了一种声明式的方式来定义和管理复杂的状态转换逻辑。

val (
    currentState,
    canTransition,
    transition,
    history,
    reset,
    canGoBack,
    goBack,
    getAvailableEvents,
    context,
) = useStateMachine(
    machineGraph = machineGraph,
)

返回的元组包含以下内容:

  • currentState: 当前状态
  • canTransition:判断是否可以发生执行事件
  • transition: 发送事件的函数
  • history: 状态历史记录
  • reset: 重置状态机的函数
  • canGoBack: 是否可以回退的标志
  • goBack: 回退到上一个状态的函数
  • getAvailableEvents:当前状态下可用的事件
  • context: 当前上下文

使用示例:

// 定义状态机图
val machineGraph = createMachine<LoadingState, LoadingEvent, Int> {
    context(1) // 初始上下文
    initial(LoadingState.IDLE) // 初始状态
    // 提供了两种 DSL 方式来创建状态机图
    state(LoadingState.IDLE) {
        on(LoadingEvent.START) {
            target(LoadingState.LOADING)
            action { ctx, e -> ctx + 1 } // 更新上下文
        }
    }
    // 另一种 DSL 方式
    states {
        LoadingState.LOADING {
            on(LoadingEvent.SUCCESS) { target(LoadingState.SUCCESS) }
            on(LoadingEvent.ERROR) { target(LoadingState.ERROR) }
        }
        // 更多状态定义...
    }
}

// 使用状态机
val (
    currentState,
    canTransition,
    transition,
    history,
    reset,
    canGoBack,
    goBack,
    getAvailableEvents,
    context,
) = useStateMachine(
    machineGraph = machineGraph,
)

// 显示当前状态
Text(text = "Current state: ${state.value}")
Text(text = "Context: ${context.value}")

// 发送事件
Button(onClick = { transition(LoadingEvent.START) }) { Text("Start") }

useThrottle

useThrottle 是一个用于创建节流值的 Hook。它接受一个值和一个配置对象,并返回一个在指定时间内最多更新一次的节流值。

val throttledValue by useThrottle(
    value = counter,
    optionsOf = {
        wait = 1000.milliseconds
        leading = true
        trailing = true
    }
)

这个 Hook 在处理频繁触发的事件(如滚动、调整大小)时特别有用,可以限制处理频率。

除了 useThrottle,还有两个相关的 Hook:

  • useThrottleFn: 创建一个节流函数
  • useThrottleEffect: 创建一个节流副作用

useSelector/useDispatch

useSelectoruseDispatch 是用于 Redux 状态管理的 Hook。

useSelector

useSelector 用于从 Redux 状态中选择特定的部分。它接受一个选择器函数,该函数从状态中提取所需的数据。

val count by useSelector { state: AppState -> state.count }

useDispatch

useDispatch 用于获取 Redux 的 dispatch 函数,该函数用于发送 action 来更新状态。

val dispatch = useDispatch<AppAction>()

// 使用 dispatch 发送 action
Button(onClick = { dispatch(IncrementAction) }) { Text("Increment") }

使用示例:

// 创建 Redux store
val store = createStore {
    counterReducer with 0
    todoReducer with emptyList()
}

// 使用ReduxProvider组件向下暴露状态
ReduxProvider(store = store) {
    // Components can now access the store
    Column {
        CounterComponent()
    }
}

// 在组件中使用
@Composable
fun CounterComponent() {
    // 选择状态
    val count by useSelector { state: AppState -> state.count }
    
    // 获取 dispatch 函数
    val dispatch = useDispatch<AppAction>()
    
    // 使用状态和 dispatch
    Text(text = "Count: $count")
    Button(onClick = { dispatch(IncrementAction) }) { Text("+") }
    Button(onClick = { dispatch(DecrementAction) }) { Text("-") }
}
Clone this wiki locally