-
Notifications
You must be signed in to change notification settings - Fork 5
SetValueFn改版
Junerver Hou edited this page Nov 29, 2024
·
3 revisions
在修改状态时,我们经常需要使用当前状态的值进行计算,将结果作为新值赋值给状态,这是一个非常常见的场景。
在过去我们使用 useGetState
时可以这样
val (state, setState, getState) = useGetState(default)
fun add() {
setState(getState() + 1)
}
这里的 setState
就是一个 SetValueFn<T>
类型的函数,通过调用它传递一个新的值,来变更状态这很平常,但是当我们的新状态值是基于旧状态值计算得出时。
它看起来有一点不够优雅,需要调用getState()
来获取值,但是没办法,为了延时读取状态的值,避免不必要的触发重组,这是不得已的,你也可以使用 state.value
他们是等效的。
另外它与我们在 React 中的使用方法是不同的,在 React 中 useState
解构出来的 set 函数可以传递值也可以传递从上一个状态计算出来的函数。
在 Kotlin 2.1.0 中,我们终于可以获得和在 React 中一致的体验,现在 set
函数的签名从 SetValueFn<T>
变更为 SetValueFn<SetterEither<T>>
。你的旧代码会因为类型推断报错,需要手动导入:
import xyz.junerver.compose.hooks.invoke
现在你可以这样使用:
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
函数来传递给组件,由于签名的变更,你需要调用 left()
函数,比如过去的写法:
@Composable
private fun Copy() {
val (state, setState) = useGetState("")
val (copy, _) = useClipboard()
Column {
TextField(
value = state.value,
onValueChange = setState, // 直接将setState传参
label = { Text("Text to copy") }
)
Button(onClick = { copy(state.value) }) {
Text("Copy to clipboard")
}
}
}
现在你需要:
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(), // 在解构出的 set 函数上调用 left 函数
label = { Text("Text to copy") }
)
Button(onClick = { copy(state.value) }) {
Text("Copy to clipboard")
}
}
}
left
函数很简单,它将 (Either<T, (T)->T>)->Unit
转成 (T)->Unit