-
Notifications
You must be signed in to change notification settings - Fork 6
Migrating from hooks to the KMP version hooks2
Here are the key considerations for migrating from hooks to the KMP version hooks2:
If you're using optionsOf
directly in hooks that require configuration and are not using named parameters:
val (resume, pause, isActive) = useInterval(
optionsOf {
initialDelay = 2.seconds
period = 1.seconds
}
)
You need to modify it to:
val (resume, pause, isActive) = useInterval(
optionsOf = {
initialDelay = 2.seconds
period = 1.seconds
}
)
The RequestOptions parameters debounceOptions
and throttleOptions
should be replaced by their respective optionOf
functions:
DebounceOptions.optionOf { }
ThrottleOptions.optionOf { }
Or use the new parameters: debounceOptionsOf
, throttleOptionsOf
. In the future version, the actual parameters will be changed to internal
access
Steps for Replacement:
Step 1: Replace debounceOptions
and throttleOptions
Replace debounceOptions = optionsOf {
with debounceOptions = DebounceOptions.optionOf {
Replace throttleOptions = optionsOf {
with throttleOptions = ThrottleOptions.optionOf {
Step 2: Globally replace options = optionsOf {
with optionsOf = {
Step 3: Replace optionsOf {
with optionsOf = {
This function should rarely be called on the user side since all functions requiring default parameters are already assigned. If you do need a default option object, use Options.optionOf {}
.
For pure Android projects, use the following dependency:
implementation("xyz.junerver.compose:hooks2-android:<latest_release>")
In previous versions, most APIs directly returned the value of the state for ease of use, which was convenient but introduced potential performance issues. For example:
@Composable
private fun TestDeferReads() {
var byState by useState("default1")
val (state, setState, getState) = useGetState("getState")
Column(modifier = Modifier.randomBackground().size(200.dp, 300.dp)) {
// by delegate
Button(onClick = {
byState += "1"
}) { Text(byState) }
// triple destructuring
Button(onClick = {
setState(getState() + "2")
}) { Text(state) }
}
}
When clicking the first button, the background color of the Column doesn't change, indicating that the component hasn't been recomposed. However, clicking the second button changes the Column background color, indicating a recomposition occurred.
The reason is simple: in Compose, reading the state triggers recomposition. Components only recompose if they read the State. If the State is declared but its value is not directly read, changes in State will not cause recomposition.
In complex pages with a large number of inline components like Column, such recomposition can lead to performance issues.
Thus, in hooks2, the value of the state is no longer returned directly (i.e., reading the value doesn't happen in the hook call). Instead, a read-only state is returned, and the value can be accessed using state.value
in the component (lazy reading).
In short, the hook will no longer return the state value T, but instead return the state State.
Hooks affected by this change:
useGetState
useBoolean
useCounter
useCountdown
useDebounce
useResetState
useReducer
useSelector
useTimestamp
useInterval
useThrottle
usePrevious
useUndo
useNow
useRequest
For hooks that return a tuple, you need to modify the code to use state.value
to access the state value. For hooks like useDebounce
, useThrottle
, useSelector
, etc., which only return a state, you can simply change =
to by
.
Example:
// Before
val (state, setState, getState) = useGetState("getState")
Column(modifier = Modifier.randomBackground().size(200.dp, 300.dp)) {
Button(onClick = {
setState(getState() + "1")
}) { Text(state) } // You can directly use the state value here
}
// After
val (state, setState, getState) = useGetState("getState")
Column(modifier = Modifier.randomBackground().size(200.dp, 300.dp)) {
Button(onClick = {
setState(getState() + "2")
}) { Text(state.value) } // Change to state.value
}
Kotlin only has two official tuple types, Pair and Triple. In the past projects, the tuple types provided by Arrow-KT were used, which were based on the built-in destructuring declaration of data class
In the use of destructuring, the destructuring capability provided by kt is weak and the readability is also poor. In view of the promise of kotlin conf 24 to provide better name-based destructuring in the future.
At present, the return value has been temporarily changed from the tuple class to the more readable XxxHolder
class in hooks2