-
Notifications
You must be signed in to change notification settings - Fork 7
SetValueFn改版
Junerver Hou edited this page Nov 29, 2024
·
10 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(),
label = { Text("Text to copy") }
)
Button(onClick = { copy(state.value) }) {
Text("Copy to clipboard")
}
}
}left 函数很简单,它将 (Either<T, (T)->T>)->Unit 转成 (T)->Unit